(function (angular) {
	angular.module('ui.grid')
		.directive('uiGridCustomerColumnResizer', uiGridCustomerColumnResizer)
		.directive('uiGridMenuCustomerButton', uiGridMenuCustomerButton)
		.directive('uiGridCustomerMenuItem', uiGridCustomerMenuItem)
		.directive('uiGridCustomerAutoResize', uiGridCustomerAutoResize)
		.directive('uiGridCustomerPagination', uiGridCustomerPagination)
		.service('uiGridOperationService', uiGridOperationService)
		.directive('uiGridOperation', uiGridOperation)
		.directive('uiGridOperationRowHeaderButtons', uiGridOperationRowHeaderButtons)
		.directive('uiGridOperationHeaderButtons', uiGridOperationHeaderButtons)
		.directive('uiGridEolOperation', uiGridEolOperation)
		.directive('uiGridCustomerScrollbar', uiGridCustomerScrollbar)
		.run(uiGridOperationTemplates);

	uiGridCustomerScrollbar.$inject = ['$timeout', '$parse', '$window', 'gridUtil', 'ScrollEvent', 'uiGridConstants'];
	function uiGridCustomerScrollbar($timeout, $parse, $window, gridUtil, ScrollEvent, uiGridConstants) {
		var uiGridCustomerScrollbarOptions = ['handlers', 'wheelSpeed', 'wheelPropagation', 'swipeEasing', 'minScrollbarLength', 'maxScrollbarLength', 'scrollingThreshold', 'useBothWheelAxes', 'suppressScrollX',
			'suppressScrollY', 'scrollXMarginOffset', 'scrollYMarginOffset',];
		return {
			priority: -200,
			transclude: true,
			replace: true,
			require: ['^uiGrid', '^uiGridRenderContainer'],
			template: '<div ng-transclude class="open" ng-click="clickEvent($event)"></div>',
			link: {
				pre: function ($scope, $elem, $attrs, controllers) {
					var jqWindow = angular.element($window);
					var options = {};
					var perfect;
					var uiGridCtrl = controllers[0];
					var grid = uiGridCtrl.grid;
					var containerCtrl = controllers[1];
					var rowContainer = containerCtrl.rowContainer;
					var colContainer = containerCtrl.colContainer;
					grid._scrollBars = grid._scrollBars || [];
					$scope.scrollHandler = function (position) {
						var newScrollTop = position.scrollTop;
						var newScrollLeft = position.scrollLeft;//gridUtil.normalizeScrollLeft($elem, grid);

						var vertScrollPercentage = rowContainer.scrollVertical(newScrollTop);
						var horizScrollPercentage = colContainer.scrollHorizontal(newScrollLeft);

						var scrollEvent = new ScrollEvent(grid, rowContainer, colContainer, ScrollEvent.Sources.ViewPortScroll);
						scrollEvent.newScrollLeft = newScrollLeft;
						scrollEvent.newScrollTop = newScrollTop;
						if (horizScrollPercentage > -1) {
							scrollEvent.x = { percentage: horizScrollPercentage };
						}

						if (vertScrollPercentage > -1) {
							scrollEvent.y = { percentage: vertScrollPercentage };
						}

						grid.scrollContainers($scope.$parent.containerId, scrollEvent);
						angular.forEach(grid._scrollBars, function (scrollbar) {
							if (perfect != scrollbar) {
								scrollbar.lastScrollTop = perfect.lastScrollTop;
								scrollbar.element.scrollLeft = perfect.element.scrollLeft;

								scrollbar.lastScrollLeft = perfect.lastScrollLeft;
								scrollbar.element.scrollTop = perfect.element.scrollTop;

								scrollbar.onScroll();
							}
						});
					}

					for (var i = 0, l = uiGridCustomerScrollbarOptions.length; i < l; i++) {
						var opt = uiGridCustomerScrollbarOptions[i];

						if ($attrs[opt] !== undefined) {
							options[opt] = $parse($attrs[opt])();
						}
					}

					if (grid.options.enableHorizontalScrollbar == 0) {
						options['suppressScrollX'] = true;
					}
					if (grid.options.enableVerticalScrollbar == 0) {
						options['suppressScrollY'] = true;
					}

					$scope.clickEvent = function ($event) {
						var element = $event.srcElement || $event.target;
						element = angular.element(element);
						if (element && (element.hasClass('ps__rail-x') || element.hasClass('ps__rail-y') || element.hasClass('ps__thumb-x') || element.hasClass('ps__thumb-y'))) {
							$event.stopPropagation();
						}
					};
					$scope.$evalAsync(function () {
						perfect = new PerfectScrollbar($elem[0], options);
						grid._scrollBars.push(perfect);
						var onScrollHandler = $parse($attrs.onScroll)($scope);
						var onScrollYEndHandler = $parse($attrs.onScrollYEnd)($scope);
						if (onScrollYEndHandler) {
							$elem.on('ps-y-reach-end', function () {
								var scrollTop = $elem.prop('scrollTop');
								var scrollHeight = $elem.prop('scrollHeight') - $elem[0].clientHeight;
								var scrollLeft = $elem.prop('scrollLeft');
								var scrollWidth = $elem.prop('scrollWidth') - $elem[0].clientWidth;

								onScrollYEndHandler({
									scrollTop: scrollTop,
									scrollHeight: scrollHeight,
									scrollLeft: scrollLeft,
									scrollWidth: scrollWidth
								});
							});
						}
						if (onScrollHandler) {
							var mouseWheeltoBind = ('onwheel' in document || document.documentMode >= 9) ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
							var renderContainer = angular.element($elem[0].parentElement.parentElement);
							angular.forEach(mouseWheeltoBind, function (bind) {
								var cbs = renderContainer.data('mousewheel-callbacks');
								angular.forEach(cbs, function (fn) {
									renderContainer.off(mouseWheeltoBind[--i], fn);
								});
							});
							$elem.on('scroll', function () {
								var scrollTop = $elem.prop('scrollTop');
								var scrollHeight = $elem.prop('scrollHeight') - $elem[0].clientHeight;
								var scrollLeft = $elem.prop('scrollLeft');
								var scrollWidth = $elem.prop('scrollWidth') - $elem[0].clientWidth;

								$scope.$apply(function () {
									onScrollHandler({
										scrollTop: scrollTop,
										scrollHeight: scrollHeight,
										scrollLeft: scrollLeft,
										scrollWidth: scrollWidth
									});
								});
							});
						}
					});

					// Automatically update when content height changes
					$scope.$watch(function () {
						return $elem.prop('scrollHeight');
					}, function (newValue, oldValue) {
						if (newValue) {
							update('contentSizeChange');
						}
					});
					$scope.$on('scrollbar-resize', function ($event) {
						if (perfect) {
							perfect.update('mouseenter');
						}
						if ($event.preventDefault) {
							$event.preventDefault();
						}
						if ($event.stopPropagation) {
							$event.stopPropagation();
						}
					});
					function update(event) {
						$scope.$evalAsync(function () {
							if ($attrs.scrollDown == 'true' && event != 'mouseenter') {
								setTimeout(function () {
									$elem[0].scrollTop = $elem.prop("scrollHeight");
								}, 100);
							}
							if (perfect) {
								perfect.update();
							}
						});
					}

					// This is necessary when you don't watch anything with the scrollbar
					$elem.on('mouseenter', function () {
						update('mouseenter');
					});

					// Possible future improvement: check the type here and use the appropriate watch for non-arrays
					if ($attrs.refreshOnChange) {
						$scope.$watchCollection($attrs.refreshOnChange, function () {
							update();
						});
					}

					// Rebuild on window resize
					if ($attrs.refreshOnResize) {
						jqWindow.on('resize', function () {
							update();
						});
					}

					if ($attrs.updateOn) {
						$attrs.updateOn.split(' ').forEach(function (eventName) {
							$scope.$on(eventName, update);
						});
					}

					// Unbind resize event and destroy instance
					$elem.on('$destroy', function () {
						$elem.off();
						jqWindow.off('resize', function () {
							update();
						});
						if (perfect) {
							perfect.destroy();
							perfect = null;
						}
					});
				}
			}
		};
	}

	uiGridCustomerColumnResizer.$inject = ['$document', 'gridUtil', 'uiGridConstants', 'uiGridResizeColumnsService', '$injector'];
	function uiGridCustomerColumnResizer($document, gridUtil, uiGridConstants, uiGridResizeColumnsService, $injector) {//change db click logic
		var resizeOverlay = angular.element('<div class="ui-grid-resize-overlay"></div>');

		var resizer = {
			priority: 0,
			scope: {
				col: '=',
				position: '@',
				renderIndex: '='
			},
			require: '?^uiGrid',
			link: function ($scope, $elm, $attrs, uiGridCtrl) {
				var startX = 0,
					x = 0,
					gridLeft = 0,
					rtlMultiplier = 1;

				//when in RTL mode reverse the direction using the rtlMultiplier and change the position to left
				if (uiGridCtrl.grid.isRTL()) {
					$scope.position = 'left';
					rtlMultiplier = -1;
				}

				if ($scope.position === 'left') {
					$elm.addClass('left');
				}
				else if ($scope.position === 'right') {
					$elm.addClass('right');
				}

				// Refresh the grid canvas
				//   takes an argument representing the diff along the X-axis that the resize had
				function refreshCanvas(xDiff) {
					// Then refresh the grid canvas, rebuilding the styles so that the scrollbar updates its size
					uiGridCtrl.grid.refreshCanvas(true).then(function () {
						uiGridCtrl.grid.queueGridRefresh();
					});
				}

				// Check that the requested width isn't wider than the maxWidth, or narrower than the minWidth
				// Returns the new recommended with, after constraints applied
				function constrainWidth(col, width) {
					var newWidth = width;

					// If the new width would be less than the column's allowably minimum width, don't allow it
					if (col.minWidth && newWidth < col.minWidth) {
						newWidth = col.minWidth;
					}
					else if (col.maxWidth && newWidth > col.maxWidth) {
						newWidth = col.maxWidth;
					}

					return newWidth;
				}


				/*
				 * Our approach to event handling aims to deal with both touch devices and mouse devices
				 * We register down handlers on both touch and mouse.  When a touchstart or mousedown event
				 * occurs, we register the corresponding touchmove/touchend, or mousemove/mouseend events.
				 *
				 * This way we can listen for both without worrying about the fact many touch devices also emulate
				 * mouse events - basically whichever one we hear first is what we'll go with.
				 */
				function moveFunction(event, args) {
					if (event.originalEvent) { event = event.originalEvent; }
					event.preventDefault();

					x = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;

					if (x < 0) { x = 0; }
					else if (x > uiGridCtrl.grid.gridWidth) { x = uiGridCtrl.grid.gridWidth; }

					var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);

					// Don't resize if it's disabled on this column
					if (col.colDef.enableColumnResizing === false) {
						return;
					}

					if (!uiGridCtrl.grid.element.hasClass('column-resizing')) {
						uiGridCtrl.grid.element.addClass('column-resizing');
					}

					// Get the diff along the X axis
					var xDiff = x - startX;

					// Get the width that this mouse would give the column
					var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);

					// check we're not outside the allowable bounds for this column
					x = x + (constrainWidth(col, newWidth) - newWidth) * rtlMultiplier;

					resizeOverlay.css({ left: x + 'px' });

					uiGridCtrl.fireEvent(uiGridConstants.events.ITEM_DRAGGING);
				}


				function upFunction(event, args) {
					if (event.originalEvent) { event = event.originalEvent; }
					event.preventDefault();

					uiGridCtrl.grid.element.removeClass('column-resizing');

					resizeOverlay.remove();

					// Resize the column
					x = (event.changedTouches ? event.changedTouches[0] : event).clientX - gridLeft;
					var xDiff = x - startX;

					if (xDiff === 0) {
						// no movement, so just reset event handlers, including turning back on both
						// down events - we turned one off when this event started
						offAllEvents();
						onDownEvents();
						return;
					}

					var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);

					// Don't resize if it's disabled on this column
					if (col.colDef.enableColumnResizing === false) {
						return;
					}

					// Get the new width
					var newWidth = parseInt(col.drawnWidth + xDiff * rtlMultiplier, 10);

					// check we're not outside the allowable bounds for this column
					col.width = constrainWidth(col, newWidth);
					col.hasCustomWidth = true;

					refreshCanvas(xDiff);

					uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);

					// stop listening of up and move events - wait for next down
					// reset the down events - we will have turned one off when this event started
					offAllEvents();
					onDownEvents();
				}


				var downFunction = function (event, args) {
					if (event.originalEvent) { event = event.originalEvent; }
					event.stopPropagation();

					// Get the left offset of the grid
					// gridLeft = uiGridCtrl.grid.element[0].offsetLeft;
					gridLeft = uiGridCtrl.grid.element[0].getBoundingClientRect().left;

					// Get the starting X position, which is the X coordinate of the click minus the grid's offset
					startX = (event.targetTouches ? event.targetTouches[0] : event).clientX - gridLeft;

					// Append the resizer overlay
					uiGridCtrl.grid.element.append(resizeOverlay);

					// Place the resizer overlay at the start position
					resizeOverlay.css({ left: startX });

					// Add handlers for move and up events - if we were mousedown then we listen for mousemove and mouseup, if
					// we were touchdown then we listen for touchmove and touchup.  Also remove the handler for the equivalent
					// down event - so if we're touchdown, then remove the mousedown handler until this event is over, if we're
					// mousedown then remove the touchdown handler until this event is over, this avoids processing duplicate events
					if (event.type === 'touchstart') {
						$document.on('touchend', upFunction);
						$document.on('touchmove', moveFunction);
						$elm.off('mousedown', downFunction);
					} else {
						$document.on('mouseup', upFunction);
						$document.on('mousemove', moveFunction);
						$elm.off('touchstart', downFunction);
					}
				};

				var onDownEvents = function () {
					$elm.on('mousedown', downFunction);
					$elm.on('touchstart', downFunction);
				};

				var offAllEvents = function () {
					$document.off('mouseup', upFunction);
					$document.off('touchend', upFunction);
					$document.off('mousemove', moveFunction);
					$document.off('touchmove', moveFunction);
					$elm.off('mousedown', downFunction);
					$elm.off('touchstart', downFunction);
				};

				onDownEvents();


				// On doubleclick, resize to fit all rendered cells
				var dblClickFn = function (event, args) {
					event.stopPropagation();

					var col = uiGridResizeColumnsService.findTargetCol($scope.col, $scope.position, rtlMultiplier);

					// Don't resize if it's disabled on this column
					if (col.colDef.enableColumnResizing === false) {
						return;
					}
					var storageService = $injector.get('storageService');
					var setting = storageService.getTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_')) || {};
					var newWidth = setting.width && setting.width[col.field] ? setting.width[col.field].width : col.drawnWidth;
					xDiff = newWidth - col.drawnWidth;
					col.width = newWidth;
					col.hasCustomWidth = true;

					refreshCanvas(xDiff);

					uiGridResizeColumnsService.fireColumnSizeChanged(uiGridCtrl.grid, col.colDef, xDiff);
				};
				$elm.on('dblclick', dblClickFn);

				$elm.on('$destroy', function () {
					$elm.off('dblclick', dblClickFn);
					offAllEvents();
				});
			}
		};

		return resizer;
	}

	uiGridMenuCustomerButton.$inject = ['gridUtil', 'uiGridConstants', 'uiGridGridMenuService', 'i18nService', '$timeout', '$injector', 'Constants'];
	function uiGridMenuCustomerButton(gridUtil, uiGridConstants, uiGridGridMenuService, i18nService, $timeout, $injector, Constants) {//add show all and normal
		return {
			priority: 0,
			scope: true,
			require: ['^uiGrid'],
			templateUrl: 'ui-grid/ui-grid-menu-button',
			replace: true,

			link: function ($scope, $elm, $attrs, controllers) {
				var uiGridCtrl = controllers[0], storageService = $injector.get('storageService');

				// For the aria label
				$scope.i18n = {
					aria: i18nService.getSafeText('gridMenu.aria')
				};

				uiGridGridMenuService.initialize($scope, uiGridCtrl.grid);
				uiGridCtrl.grid.options.displayStyle = uiGridCtrl.grid.options.displayStyle || 'normal';
				if (uiGridCtrl.grid.api.colResizable) {
					uiGridCtrl.grid.api.colResizable.on.columnSizeChanged($scope, function (colDef, deltaChange) {
						if (storageService) {
							var setting = storageService.getTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_')) || {};
							var column;
							for (i = 0; i < uiGridCtrl.grid.columns.length; i++) {
								if (uiGridCtrl.grid.columns[i].field == colDef.field) {
									column = uiGridCtrl.grid.columns[i];
									break;
								}
							}
							setting.width = setting.width || {};
							if (!setting.width[colDef.field]) {
								setting.width[colDef.field] = {
									width: colDef.width,
									minWidth: colDef.minWidth
								};
							}
							setting.width['_' + uiGridCtrl.grid.options.displayStyle] = setting.width['_' + uiGridCtrl.grid.options.displayStyle] || {};
							setting.width['_' + uiGridCtrl.grid.options.displayStyle][colDef.field] = setting.width['_' + uiGridCtrl.grid.options.displayStyle][colDef.field] || {};
							setting.width['_' + uiGridCtrl.grid.options.displayStyle][colDef.field].adjustWidth = column.width;
							setting.displayStyle = uiGridCtrl.grid.options.displayStyle;
							storageService.saveTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_'), setting);
						}
					});
				}
				if (uiGridCtrl.grid.api.colMovable && uiGridCtrl.grid.api.colMovable.raise) {
					uiGridCtrl.grid.api.colMovable.raise.columnPositionChanged = function (colDef, originalPosition, newPosition) {
						if (storageService) {
							var order = [];
							if (uiGridCtrl.grid.api.grid.moveColumns && uiGridCtrl.grid.api.grid.moveColumns.orderCache) {
								angular.forEach(uiGridCtrl.grid.api.grid.moveColumns.orderCache, function (orderCache) {
									order.push(orderCache.colDef.field);
								});
							}
							storageService.saveTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_'), {
								displayStyle: uiGridCtrl.grid.api.grid.options.displayStyle,
								order: order
							});
							if (uiGridCtrl.grid.options.displayStyle == 'all') {
								$scope.showAll();
							} else {
								$scope.showNormal();
							}
						}
					};
				}
				$scope.$on(Constants.NOTIFY_HIDE_COLUMN, function (event, args) {
					if (uiGridCtrl.grid.options.displayStyle == 'all') {
						$scope.showAll();
					} else {
						$scope.showNormal();
					}
				});
				$scope.shown = false;
				$scope.toggleDisplayStyle = function () {
					if ($scope.switchChecked) {
						uiGridCtrl.grid.options.displayStyle = 'all';
						$scope.showAll();
					} else {
						uiGridCtrl.grid.options.displayStyle = 'normal'
						$scope.showNormal();
					}
					storageService.saveTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_'), {
						displayStyle: uiGridCtrl.grid.options.displayStyle
					});
				};
				$scope.showAll = function () {
					var tableSetting, needSaveSetting;
					tableSetting = storageService.getTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_'));
					angular.forEach(uiGridCtrl.grid.columns, function (column, index) {
						var originalSetting;
						if (column.field && column.field.indexOf('RowHeaderCol') < 0) {
							if (tableSetting && tableSetting.width && tableSetting.width[column.field]) {
								originalSetting = tableSetting.width[column.field];
							} else if (column.colDef.minWidth || column.colDef.width) {
								needSaveSetting = true;
								tableSetting = tableSetting || {};
								originalSetting = tableSetting[column.colDef.field] = {
									width: column.colDef.width || column.width,
									minWidth: column.colDef.minWidth
								};
							}
							if (tableSetting && tableSetting.width && tableSetting.width['_' + uiGridCtrl.grid.options.displayStyle] && tableSetting.width['_' + uiGridCtrl.grid.options.displayStyle][column.field]) {
								column.width = tableSetting.width['_' + uiGridCtrl.grid.options.displayStyle][column.field].adjustWidth;
							} else {
								column.width = '*';
							}
							column.minWidth = column.colDef.minWidth ? 30 : null;
						}
					});
					if (needSaveSetting) {
						storageService.saveTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_'), {
							displayStyle: uiGridCtrl.grid.options.displayStyle,
							width: tableSetting
						});
					}
					uiGridCtrl.grid.refreshCanvas(true).then(function () {
						angular.forEach(uiGridCtrl.grid._scrollBars, function (scrollbar) {
							scrollbar.update();
						});
					});
				};
				$scope.showNormal = function () {
					var tableSetting;
					tableSetting = storageService.getTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_'));
					angular.forEach(uiGridCtrl.grid.columns, function (column) {
						var originalSetting;
						if (column.field && column.name.indexOf('RowHeaderCol') < 0) {
							if (tableSetting && tableSetting.width && tableSetting.width[column.field]) {
								originalSetting = tableSetting.width[column.field];
							}
							if (tableSetting && tableSetting.width && tableSetting.width['_' + uiGridCtrl.grid.options.displayStyle] && tableSetting.width['_' + uiGridCtrl.grid.options.displayStyle][column.field]) {
								column.colDef.width = tableSetting.width['_' + uiGridCtrl.grid.options.displayStyle][column.field].adjustWidth;
							} else if (originalSetting) {
								column.colDef.width = originalSetting.width;
							}
							column.colDef.minWidth = originalSetting ? originalSetting.minWidth : column.colDef.minWidth;
						}
					});
					uiGridCtrl.grid.refreshCanvas(true).then(function () {
						angular.forEach(uiGridCtrl.grid._scrollBars, function (scrollbar) {
							scrollbar.update('mouseenter');
						});
					});
					uiGridCtrl.grid.api.core.notifyDataChange(uiGridConstants.dataChange.COLUMN);
				};
				$scope.toggleMenu = function () {
					if ($scope.shown) {
						$scope.$broadcast('hide-menu');
						$scope.shown = false;
					} else {
						$scope.menuItems = uiGridGridMenuService.getMenuItems($scope);
						$scope.$broadcast('show-menu');
						$scope.shown = true;
					}
				};

				$scope.$on('menu-hidden', function () {
					$scope.shown = false;
					gridUtil.focus.bySelector($elm, '.ui-grid-icon-container');
				});
				if (uiGridCtrl.grid.options.displayStyle == 'all') {
					$scope.showAll();
				} else {
					$scope.showNormal();
				}
				function gridResize() {
					uiGridCtrl.grid.gridWidth = gridUtil.elementWidth($elm);
					uiGridCtrl.grid.gridHeight = gridUtil.elementHeight($elm);
					uiGridCtrl.grid.refreshCanvas(true);
				}
			}
		};
	}

	uiGridCustomerMenuItem.$inject = ['gridUtil', '$compile', 'i18nService', 'uiGridMoveColumnService', 'uiGridResizeColumnsService', '$injector'];
	function uiGridCustomerMenuItem(gridUtil, $compile, i18nService, uiGridMoveColumnService, uiGridResizeColumnsService, $injector) { // change menu items
		return {
			priority: 0,
			scope: {
				name: '=',
				active: '=',
				action: '=',
				icon: '=',
				shown: '=',
				context: '=',
				templateUrl: '=',
				leaveOpen: '=',
				screenReaderOnly: '=',
				index: '='
			},
			require: ['?^uiGrid'],
			templateUrl: 'ui-grid/uiGridMenuItem',
			replace: false,
			compile: function () {
				return {
					pre: function ($scope, $elm) {
						if ($scope.templateUrl) {
							gridUtil.getTemplate($scope.templateUrl)
								.then(function (contents) {
									var template = angular.element(contents);

									var newElm = $compile(template)($scope);
									$elm.replaceWith(newElm);
								}).catch(angular.noop);
						}
					},
					post: function ($scope, $elm, $attrs, controllers) {
						var uiGridCtrl = controllers[0];

						$scope.getGrid = function () {
							return uiGridCtrl.grid;
						};

						// TODO(c0bra): validate that shown and active are functions if they're defined. An exception is already thrown above this though
						// if (typeof($scope.shown) !== 'undefined' && $scope.shown && typeof($scope.shown) !== 'function') {
						// throw new TypeError("$scope.shown is defined but not a function");
						// }
						if (typeof ($scope.shown) === 'undefined' || $scope.shown === null) {
							$scope.shown = function () { return true; };
						}

						$scope.visible = $scope.context ? $scope.context.gridCol.colDef.visible : undefined;

						$scope.itemShown = function () {
							var context = {};
							if ($scope.context) {
								context.context = $scope.context;
							}

							if (typeof (uiGridCtrl) !== 'undefined' && uiGridCtrl) {
								context.grid = uiGridCtrl.grid;
							}

							return $scope.shown.call(context);
						};

						$scope.itemAction = function ($event, title) {
							$event.stopPropagation();

							if (typeof ($scope.action) === 'function') {
								var context = {};

								if ($scope.context) {
									context.context = $scope.context;
								}

								// Add the grid to the function call context if the uiGrid controller is present
								if (typeof (uiGridCtrl) !== 'undefined' && uiGridCtrl) {
									context.grid = uiGridCtrl.grid;
								}
								$scope.action.call(context, $event, title);
								adjustColumnWidth();
								$scope.visible = $scope.context.gridCol.colDef.visible;
								if ($injector.get('storageService')) {
									var visible = {};
									visible[$scope.context.gridCol.colDef.field] = $scope.context.gridCol.colDef.visible;
									$injector.get('storageService').saveTableSetting(($scope.$root.pageId + ':' + uiGridCtrl.grid.options.name).split('.').join('_'), {
										'displayStyle': uiGridCtrl.grid.options.displayStyle,
										'visible': visible
									});
								}
								$scope.$emit(Constants.NOTIFY_HIDE_COLUMN);
								if (!$scope.leaveOpen) {
									$scope.$emit('hide-menu');
								} else {
									// Maintain focus on the selected item
									/*var correctParent = $event.target.parentElement;
				
									// nodeName of 'I' means target is i element, need the next parent
									if (angular.element($event.target)[0].nodeName === 'I') {
									  correctParent = correctParent.parentElement;
									}
				
									gridUtil.focus.bySelector(correctParent, 'button[type=button]', true);*/
								}
							}
						};

						$scope.itemMoved = function ($event) {
							var i, col, columns;
							col = $scope.context.gridCol.colDef;
							columns = uiGridCtrl.grid.columns;
							if ((angular.isUndefined(col.visible) || col.visible === true)) {
								for (i = 0; i < columns.length; i++) {
									if ((angular.isUndefined(columns[i].colDef.visible) || columns[i].colDef.visible === true) && $scope.context.gridCol.uid == columns[i].uid) {
										uiGridMoveColumnService.redrawColumnAtPosition(uiGridCtrl.grid, i, i - 1);
										break;
									}
								}
								uiGridMoveColumnService(uiGridCtrl.grid, index, index - 1);
							}
						}

						$scope.label = function () {
							var toBeDisplayed = $scope.name;

							if (typeof ($scope.name) === 'function') {
								toBeDisplayed = $scope.name.call();
							}

							return toBeDisplayed;
						};

						$scope.i18n = i18nService.get();

						function adjustColumnWidth() {
							//TODU:
						}
					}
				};
			}
		}
	}
	uiGridCustomerAutoResize.$inject = ['gridUtil', 'uiGridConstants', '$interval', '$timeout', '$window', '$document', 'ScrollEvent', 'Constants'];
	function uiGridCustomerAutoResize(gridUtil, uiGridConstants, $interval, $timeout, $window, $document, ScrollEvent, Constants) {
		return {
			require: ['uiGrid', '^?fsTabset'],
			scope: false,
			link: function ($scope, $elm, $attrs, ctrls) {
				var tabIndex, watch, cellsWatch, watchers = [], uiGridCtrl = ctrls[0], tabsetCtrl = ctrls[1], uiGrids = [];
				var resizeTimer, adjustHeightTimer;
				ScrollEvent.prototype.atTop = function (scrollTop) {
					var viewport = $elm[0].querySelector('.ui-grid-render-container-body .ui-grid-viewport');
					if (viewport && angular.element(viewport).css('overflow-y') == 'hidden') {
						return true;
					}
					return (this.y && (this.y.percentage === 0 || this.verticalScrollLength < 0) && scrollTop === 0);
				};
				ScrollEvent.prototype.atBottom = function (scrollTop) {
					var viewport = $elm[0].querySelector('.ui-grid-render-container-body .ui-grid-viewport');
					if (viewport && angular.element(viewport).css('overflow-y') == 'hidden') {
						return true;
					}
					return (this.y && (this.y.percentage === 1 || this.verticalScrollLength === 0) && scrollTop > 0);
				};
				scrollbarWidth = gridUtil.getScrollbarWidth();
				$scope.$on('$destroy', function () {
					(cellsWatch || angular.noop)();
					while (watchers.length) {
						(watchers.shift() || angular.noop)();
					}
				});
				watch = $scope.$watchGroup([function () {
					var bodyWidth = gridUtil.elementWidth($document[0].querySelector('body'));
					return $window.innerWidth - bodyWidth;
				}], function (newValues, oldValues) {
					if (!angular.equals(newValues, oldValues)) {
						gridResize();
					}
				});
				watchers.push(watch);
				if (tabsetCtrl) {
					tabIndex = tabsetCtrl.active;
					watch = $scope.$watch(function () {
						return tabsetCtrl.active;
					}, function (active) {
						if (active == tabIndex) {
							adjustHeight(uiGridCtrl.grid.renderContainers.body.renderedRows);
						}
					});
					watchers.push(watch);
				}
				angular.element($window).on('resize', function () {
					if (resizeTimer) {
						return;
					}
					resizeTimer = $interval(function () {
						var adjustRows = autoAdjustHeight();
						if (uiGridCtrl.grid.renderContainers.body.renderedRows.length > 0 && adjustRows == uiGridCtrl.grid.renderContainers.body.renderedRows.length) {
							$interval.cancel(resizeTimer);
						} else if (!uiGridCtrl.grid.renderContainers.body.renderedRows || uiGridCtrl.grid.renderContainers.body.renderedRows.length == 0) {
							$interval.cancel(resizeTimer);
						}
						resizeTimer = null;
					}, 0, false);
				});
				watch = $scope.$watchCollection(function () {
					return uiGridCtrl.grid.renderContainers.body.renderedRows;
				}, function (renderedRows) {
					adjustHeight(renderedRows);
				});
				watchers.push(watch);
				$scope.$on(Constants.NOTIFY_HIDE_COLUMN, function (event, args) {
					adjustHeight(uiGridCtrl.grid.renderContainers.body.renderedRows);
					//event.preventDefault();
					//event.stopPropagation();
				});
				$scope.$on(Constants.NOTIFY_COLLPASE_LEFT_MENU, function (event, args) {
					adjustHeight(uiGridCtrl.grid.renderContainers.body.renderedRows);
				});
				function adjustHeight(newData, oldData) {
					if (adjustHeightTimer) {
						return;
					}
					adjustHeightTimer = $interval(function () {
						var adjustRows = autoAdjustHeight();
						if (newData && newData.length > 0 && adjustRows == newData.length) {
							$interval.cancel(adjustHeightTimer);
						} else if (!newData || newData.length == 0) {
							$interval.cancel(adjustHeightTimer);
						}
						adjustHeightTimer = null;
					}, 0, false);
				}
				function autoAdjustHeight() {
					var leftCanvas, centerCanvas, rightCanvas, leftRows, centerRows, rightRows, leftGridCanvas, centerGridCanvas, rightGridCanvas, gridViewports, gridColumnFooter, gridFooter, pageBar;
					var i, e1, e2, e3, cells, cellsWatchGroup, visibleLines = 0, maxHeight, scrollbarHeight = 0, contentHeight = 0, headerHeight = 0, footerHeight = 0, scrollbarHeight = 0, filterHeight = 0, pageBarHeight = 0, maxNumberOfFilters = 0, allColumnsHaveFilteringTurnedOff;
					var adjustElements = [];
					if (uiGridCtrl.grid.options.showHeader) {
						e1 = $elm[0].querySelector(".ui-grid-render-container-left .ui-grid-header-cell-wrapper");
						e2 = $elm[0].querySelector(".ui-grid-render-container-body .ui-grid-header-cell-wrapper");
						e3 = $elm[0].querySelector(".ui-grid-render-container-right .ui-grid-header-cell-wrapper");
						leftCanvas = $elm[0].querySelector(".ui-grid-render-container-left .ui-grid-header-canvas");
						centerCanvas = $elm[0].querySelector(".ui-grid-render-container-body .ui-grid-header-canvas");
						rightCanvas = $elm[0].querySelector(".ui-grid-render-container-right .ui-grid-header-canvas");

						maxHeight = uiGridCtrl.grid.options.headerRowHeight;
						if (e1) {
							angular.element(e1).css({ height: 'auto' });
						}
						if (e2) {
							angular.element(e2).css({ height: 'auto' });
							cells = e2.querySelectorAll('.ui-grid-header-cell');
							if (cells && cells.length > 0) {
								cellsWatchGroup = [];
								angular.forEach(cells, function (cell, i) {
									cellsWatchGroup[i] = function () {
										return cell.offsetWidth;
									}
								});
								(cellsWatch || angular.noop)();
								cellsWatch = $scope.$watchGroup(cellsWatchGroup, function (newValues, oldValues) {
									if (!angular.equals(newValues, oldValues)) {
										adjustHeight(uiGridCtrl.grid.renderContainers.body.renderedRows);
									}
								});
							}
						}
						if (e3) {
							angular.element(e3).css({ height: 'auto' });
						}
						if (leftCanvas) {
							angular.element(leftCanvas).css({ height: 'auto' });
						}
						if (centerCanvas) {
							angular.element(centerCanvas).css({ height: 'auto' });
						}
						if (rightCanvas) {
							angular.element(rightCanvas).css({ height: 'auto' });
						}
						maxHeight = Math.max(maxHeight, e1 ? e1.offsetHeight : 0, e2 ? e2.offsetHeight : 0, e3 ? e3.offsetHeight : 0);
						headerHeight += maxHeight;
						if (e1) {
							angular.element(e1).css({ height: maxHeight + 'px' });
						}
						if (e2) {
							angular.element(e2).css({ height: maxHeight + 'px' });
						}
						if (e3) {
							angular.element(e3).css({ height: maxHeight + 'px' });
						}
						/*if (leftCanvas) {
							angular.element(leftCanvas).css({ height : headerHeight + 'px' });
						}
						if (centerCanvas) {
							angular.element(centerCanvas).css({ height : headerHeight + 'px' });
						}
						if (rightCanvas) {
							angular.element(rightCanvas).css({ height : headerHeight + 'px' });
						}*/
					}
					gridViewports = $elm[0].querySelectorAll('.ui-grid-viewport');
					if (!gridViewports || gridViewports.length == 0) {
						return 0;
					}
					leftGridCanvas = $elm[0].querySelector(".ui-grid-render-container-left .ui-grid-viewport .ui-grid-canvas");
					centerGridCanvas = $elm[0].querySelector(".ui-grid-render-container-body .ui-grid-viewport .ui-grid-canvas");
					rightGridCanvas = $elm[0].querySelector(".ui-grid-render-container-right .ui-grid-viewport .ui-grid-canvas");
					leftRows = leftGridCanvas ? leftGridCanvas.querySelectorAll(".grid-row") : undefined;
					centerRows = centerGridCanvas ? centerGridCanvas.querySelectorAll(".grid-row") : undefined;
					rightRows = rightGridCanvas ? rightGridCanvas.querySelectorAll(".grid-row") : undefined;
					for (i = 0; centerRows && i < centerRows.length; i++) {
						e1 = leftRows ? leftRows[i] : undefined;
						e2 = centerRows ? centerRows[i] : undefined;
						e3 = rightRows ? rightRows[i] : undefined;
						maxHeight = uiGridCtrl.grid.options.rowHeight;
						if (e1) {
							angular.element(e1).css({ height: 'auto' });
						}
						if (e2) {
							angular.element(e2).css({ height: 'auto' });
						}
						if (e3) {
							angular.element(e3).css({ height: 'auto' });
						}
						maxHeight = Math.max(maxHeight, e1 ? e1.offsetHeight : 0, e2 ? e2.offsetHeight : 0, e3 ? e3.offsetHeight : 0);
						if (uiGridCtrl.grid.options.maxRowsToShow > 0) {
							if (i < uiGridCtrl.grid.options.maxRowsToShow) {
								visibleLines++;
								contentHeight += maxHeight;
							}
						} else if (i < uiGridCtrl.grid.options.paginationPageSize || uiGridCtrl.grid.options.enableVerticalScrollbar == uiGridConstants.scrollbars.NEVER) {
							visibleLines++;
							contentHeight += maxHeight;
						}
						if (e1) {
							adjustElements.push({ element: angular.element(e1), height: maxHeight });
						}
						if (e2) {
							adjustElements.push({ element: angular.element(e2), height: maxHeight });
						}
						if (e3) {
							adjustElements.push({ element: angular.element(e3), height: maxHeight });
						}
					}

					if (uiGridCtrl.grid.options.minRowsToShow && i < uiGridCtrl.grid.options.minRowsToShow) {
						visibleLines += (uiGridCtrl.grid.options.minRowsToShow - i);
						contentHeight += uiGridCtrl.grid.options.rowHeight * (uiGridCtrl.grid.options.minRowsToShow - i);
					}

					angular.forEach(adjustElements, function (elm, height) {
						elm.element.css({ height: elm.height + 'px' });
					});

					if (!contentHeight) {
						angular.element(centerGridCanvas).css({
							height: uiGridCtrl.grid.options.rowHeight + 'px'
						});
					} else {
						angular.element(centerGridCanvas).css({
							height: 'auto'
						});
					}

					contentHeight = contentHeight ? contentHeight : uiGridCtrl.grid.options.rowHeight;
					contentHeight += (visibleLines ? visibleLines : 0);
					footerHeight = uiGridCtrl.grid.calcFooterHeight();
					if (needsHScrollbarPlaceholder()) {
						scrollbarHeight = uiGridCtrl.grid.scrollbarHeight;
					}
					if ($elm[0].querySelector(".ui-grid-render-container-body .ui-grid-viewport .ps__thumb-x") && $elm[0].querySelector(".ui-grid-render-container-body .ui-grid-viewport .ps__thumb-x").offsetHeight > 0) {
						contentHeight += $elm[0].querySelector(".ui-grid-render-container-body .ui-grid-viewport .ps__thumb-x").offsetHeight + 2;
					}
					angular.forEach(uiGridCtrl.grid.options.columnDefs, function (col) {
						if (col.hasOwnProperty('filter')) {
							if (maxNumberOfFilters < 1) {
								maxNumberOfFilters = 0;
							}
						} else if (col.hasOwnProperty('filters')) {
							if (maxNumberOfFilters < col.filters.length) {
								maxNumberOfFilters = col.filters.length;
							}
						}
					});

					if (uiGridCtrl.grid.options.enableFiltering && !maxNumberOfFilters) {
						allColumnsHaveFilteringTurnedOff = uiGridCtrl.grid.options.columnDefs.length && uiGridCtrl.grid.options.columnDefs.every(function (col) {
							return col.enableFiltering === false;
						});
						if (!allColumnsHaveFilteringTurnedOff) {
							maxNumberOfFilters = 1;
						}
					}

					filterHeight = maxNumberOfFilters * (uiGridCtrl.grid.options.showHeader ? uiGridCtrl.grid.options.headerRowHeight : 0);

					pageBar = $elm[0].querySelector(".ui-grid-pager-panel");
					if (pageBar) {
						pageBarHeight = gridUtil.elementHeight(angular.element(pageBar));
					}
					//var h = headerHeight + contentHeight + footerHeight + scrollbarHeight + filterHeight + pageBarHeight;
					var gridViewport = $elm[0].querySelector(".ui-grid-render-container-left .ui-grid-viewport");
					if (gridViewport && angular.element(gridViewport).css("height") != (contentHeight + 'px')) {
						angular.element(gridViewport).css({ height: contentHeight + 'px' });
						angular.element(gridViewport.querySelector(".scroller")).css({ height: contentHeight + 'px' });
					}
					gridViewport = $elm[0].querySelector(".ui-grid-render-container-body .ui-grid-viewport");
					if (gridViewport && angular.element(gridViewport).css("height") != ((contentHeight + scrollbarHeight) + 'px')) {
						angular.element(gridViewport).css({ height: (contentHeight + scrollbarHeight) + 'px' });
						angular.element(gridViewport.querySelector(".scroller")).css({ height: (contentHeight + scrollbarHeight) + 'px' });
						$scope.$broadcast('scrollbar-resize');
					}
					gridViewport = $elm[0].querySelector(".ui-grid-render-container-right .ui-grid-viewport");
					if (gridViewport && angular.element(gridViewport).css("height") != (contentHeight + 'px')) {
						angular.element(gridViewport).css({ height: contentHeight + 'px' });
						angular.element(gridViewport.querySelector(".scroller")).css({ height: contentHeight + 'px' });
					}

					/*if (uiGridCtrl.grid.options.enablePagination && uiGridCtrl.grid.options.enablePaginationControls) {
						h += (visibleLines ? visibleLines : 0);
					}*/
					if ($elm.css("height") != 'auto') {
						$elm.css('height', 'auto');
					}
					$timeout(function () {
						gridResize();
					}, 200);

					return centerRows ? centerRows.length : 0;
				}

				function gridResize() {
					uiGridCtrl.grid.gridWidth = gridUtil.elementWidth($elm);
					uiGridCtrl.grid.gridHeight = gridUtil.elementHeight($elm);
					uiGridCtrl.grid.refreshCanvas(true);
				}

				function needsHScrollbarPlaceholder() {
					var self = uiGridCtrl, containerBody;
					if (self.grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
						return true;
					}
					containerBody = $elm[0].querySelector('.ui-grid-render-container-body .ui-grid-viewport');
					return containerBody.scrollWidth > containerBody.offsetWidth;
				}
			}
		};
	}

	uiGridCustomerPagination.$inject = ['gridUtil', 'uiGridPaginationService'];
	function uiGridCustomerPagination(gridUtil, uiGridPaginationService) {
		return {
			priority: -200,
			scope: false,
			require: 'uiGrid',
			link: {
				pre: function ($scope, $elm, $attr, uiGridCtrl) {
					uiGridPaginationService.initializeGrid(uiGridCtrl.grid);

					gridUtil.getTemplate(uiGridCtrl.grid.options.paginationTemplate)
						.then(function (contents) {
							var template = angular.element(contents);
							if (uiGridCtrl.grid.options.paginationStyle == 'before') {
								$elm.prepend(template);
							}
							if (!uiGridCtrl.grid.options.paginationStyle || uiGridCtrl.grid.options.paginationStyle == 'after') {
								$elm.append(template);
							}
							uiGridCtrl.innerCompile(template);
						});
				}
			}
		};
	}

	uiGridOperationService.$inject = ['$q', '$templateCache', 'uiGridSelectionConstants', 'gridUtil'];
	function uiGridOperationService($q, $templateCache, uiGridSelectionConstants, gridUtil) {
		var service = {
			initializeGrid: function (grid) {
				service.defaultGridOptions(grid.options);
			},
			defaultGridOptions: function (gridOptions) {
				gridOptions.enableOperation = gridOptions.enableOperation == true;
				gridOptions.enableOperationAdd = gridOptions.addRow ? true : false;
				gridOptions.enableOperationRemoveSelected = gridOptions.enableOperationRemoveSelected !== false;
				gridOptions.enableOperationRemoveAll = gridOptions.enableOperationRemoveAll !== false;
				gridOptions.enableOperationView = gridOptions.viewRow ? true : false;
				gridOptions.enableOperationEdit = gridOptions.editRow ? true : false;
				gridOptions.enableOperationCancel = gridOptions.cancelRow ? true : false;
				gridOptions.enableOperationAddSubRow = gridOptions.addSubRow ? true : false;
				gridOptions.enableOperationRemove = gridOptions.removeRow ? true : false;
				gridOptions.enableOperationProcess = gridOptions.processRow ? true : false;
				gridOptions.enableOperationMoreProcess = gridOptions.moreProcess ? true : false;
				gridOptions.viewRowPermission = gridOptions.viewRowPermission ? gridOptions.viewRowPermission : "*";
				gridOptions.editRowPermission = gridOptions.editRowPermission ? gridOptions.editRowPermission : "*";
				gridOptions.cancelRowPermission = gridOptions.cancelRowPermission ? gridOptions.cancelRowPermission : "*";
				gridOptions.downloadRowPermission = gridOptions.downloadRowPermission ? gridOptions.downloadRowPermission : "*";
				gridOptions.addSubRowPermission = gridOptions.addSubRowPermission ? gridOptions.addSubRowPermission : "*";
				gridOptions.removeRowPermission = gridOptions.removeRowPermission ? gridOptions.removeRowPermission : "*";
				gridOptions.processRowPermission = gridOptions.processRowPermission ? gridOptions.processRowPermission : "*";

				gridOptions.enableEolOperation = gridOptions.enableEolOperation == true;
				gridOptions.enableEolOperationView = gridOptions.viewRowByEol ? true : false;
				gridOptions.enableEolOperationEdit = gridOptions.editRowByEol ? true : false;
				gridOptions.enableEolOperationCancel = gridOptions.cancelRowByEol ? true : false;
				gridOptions.enableEolOperationDownload = gridOptions.downloadRowByEol ? true : false;
				gridOptions.enableEolOperationAddSubRow = gridOptions.addSubRowByEol ? true : false;
				gridOptions.enableEolOperationRemove = gridOptions.removeRowByEol ? true : false;
				gridOptions.enableEolOperationProcess = gridOptions.processRowByEol ? true : false;
				gridOptions.enableEolOperationMoreProcess = gridOptions.moreProcessByEol ? true : false;
				gridOptions.viewRowByEolPermission = gridOptions.viewRowByEolPermission ? gridOptions.viewRowByEolPermission : "*";
				gridOptions.editRowByEolPermission = gridOptions.editRowByEolPermission ? gridOptions.editRowByEolPermission : "*";
				gridOptions.cancelRowByEolPermission = gridOptions.cancelRowByEolPermission ? gridOptions.cancelRowByEolPermission : "*";
				gridOptions.downloadRowByEolPermission = gridOptions.downloadRowByEolPermission ? gridOptions.downloadRowByEolPermission : "*";
				gridOptions.addSubRowByEolPermission = gridOptions.addSubRowByEolPermission ? gridOptions.addSubRowByEolPermission : "*";
				gridOptions.removeRowByEolPermission = gridOptions.removeRowByEolPermission ? gridOptions.removeRowByEolPermission : "*";
				gridOptions.processRowByEolPermission = gridOptions.processRowByEolPermission ? gridOptions.processRowByEolPermission : "*";
			}
		};
		return service;
	}

	uiGridOperation.$inject = ['uiGridOperationService', '$templateCache', 'uiGridConstants'];
	function uiGridOperation(uiGridOperationService, $templateCache, uiGridConstants) {
		return {
			replace: true,
			priority: 0,
			require: '^uiGrid',
			scope: false,
			compile: function () {
				return {
					pre: function ($scope, $elm, $attrs, uiGridCtrl) {
						var self = uiGridCtrl.grid;
						uiGridOperationService.initializeGrid(self);
						if (self.options.enableOperation) {
							var operationRowHeaderDef = {
								name: 'operationRowHeaderCol',
								displayName: '',
								width: calculateWidth(),
								minWidth: 10,
								cellTemplate: 'pti/operationRowHeader',
								headerCellTemplate: 'pti/operationHeaderCell',
								enableColumnResizing: false,
								enableColumnMenu: false,
								exporterSuppressExport: true,
								allowCellFocus: true
							};

							self.addRowHeaderColumn(operationRowHeaderDef, -10);
						}

						function calculateWidth() {
							var width = 30, btnSize = 0;
							if (angular.isDefined(self.options.operationRowHeaderWidth)) {
								return self.options.operationRowHeaderWidth;
							}
							if (self.options.enableOperationView) {
								btnSize++;
							}
							if (self.options.enableOperationEdit) {
								btnSize++;
							}
							if (self.options.enableOperationCancel) {
								btnSize++;
							}
							if (self.options.enableOperationDownload) {
								btnSize++;
							}
							if (self.options.enableOperationAddSubRow) {
								btnSize++;
							}
							if (self.options.enableOperationRemove) {
								btnSize++;
							}
							if (self.options.enableOperationProcess) {
								btnSize++;
							}
							if (self.options.enableOperationMoreProcess) {
								btnSize++;
							}
							return width + ((btnSize - 1) >= 0 ? (btnSize - 1) : 0) * 20;
						}
					},
					post: function ($scope, $elm, $attrs, uiGridCtrl) {

					}
				};
			}
		};
	}

	uiGridEolOperation.$inject = ['uiGridOperationService', '$templateCache', 'uiGridConstants', 'GridColumn', 'gridUtil'];
	function uiGridEolOperation(uiGridOperationService, $templateCache, uiGridConstants, GridColumn, gridUtil) {
		function eolOperationBuilder(colDef, col, gridOptions) {
			if (colDef.pinnedLeft) {
				col.grid.createRightContainer();
			} else if (colDef.pinnedRight) {
				col.grid.createLeftContainer();
			}
		}
		function addReverseOperationRowHeaderColumn(grid, colDef, order, stopColumnBuild) {
			var self = grid;

			// default order
			if (order === undefined) {
				order = 0;
			}

			var rowHeaderCol = new GridColumn(colDef, gridUtil.nextUid(), self);
			rowHeaderCol.isRowHeader = true;
			if (self.isRTL()) {
				self.createLeftContainer();
				rowHeaderCol.renderContainer = 'left';
			}
			else {
				self.createRightContainer();
				rowHeaderCol.renderContainer = 'right';
			}

			// relies on the default column builder being first in array, as it is instantiated as part of grid creation
			self.columnBuilders[0](colDef, rowHeaderCol, self.options)
				.then(function () {
					rowHeaderCol.enableFiltering = false;
					rowHeaderCol.enableSorting = false;
					rowHeaderCol.enableHiding = false;
					rowHeaderCol.headerPriority = order;
					self.rowHeaderColumns.push(rowHeaderCol);
					self.rowHeaderColumns = self.rowHeaderColumns.sort(function (a, b) {
						return a.headerPriority - b.headerPriority;
					});

					if (!stopColumnBuild) {
						self.buildColumns().then(function () {
							self.preCompileCellTemplates();
							self.queueGridRefresh();
						}).catch(angular.noop);
					}
				}).catch(angular.noop);
		}
		return {
			replace: true,
			priority: 0,
			require: '^uiGrid',
			scope: false,
			compile: function () {
				return {
					pre: function ($scope, $elm, $attrs, uiGridCtrl) {
						var self = uiGridCtrl.grid;
						if (self.options.enableEolOperation) {
							self.registerColumnBuilder(eolOperationBuilder);
							uiGridOperationService.initializeGrid(self);
							var operationRowHeaderDef = {
								name: 'eolOperationRowHeaderCol',
								displayName: 'list.title.action',
								width: calculateWidth(),
								minWidth: 30,
								cellTemplate: 'pti/eolOperationRowHeader',
								headerCellTemplate: "<div role=\"columnheader\" class=\"ui-grid-cell-contents ui-grid-header-cell-primary-focus\"><span class=\"ui-grid-header-cell-label\">{{ col.displayName | translate }}</span></div></div>",
								enableColumnResizing: false,
								enableColumnMenu: false,
								exporterSuppressExport: true,
								allowCellFocus: true,
								pinnedRight: true
							};
							addReverseOperationRowHeaderColumn(self, operationRowHeaderDef, -10);
						}

						function calculateWidth() {
							var width = 75, btnSize = 0;
							if (angular.isDefined(self.options.operationRowHeaderWidth)) {
								return self.options.operationRowHeaderWidth;
							}
							if (self.options.enableEolOperationView) {
								btnSize++;
							}
							if (self.options.enableEolOperationEdit) {
								btnSize++;
							}
							if (self.options.enableEolOperationCancel) {
								btnSize++;
							}
							if (self.options.enableEolOperationDownload) {
								btnSize++;
							}
							if (self.options.enableEolOperationAddSubRow) {
								btnSize++;
							}
							if (self.options.enableEolOperationRemove) {
								btnSize++;
							}
							if (self.options.enableEolOperationProcess) {
								btnSize++;
							}
							if (self.options.enableEolOperationMoreProcess) {
								btnSize++;
							}
							return width + ((btnSize - 2) >= 0 ? (btnSize - 2) : 0) * 20;
						}
					},
					post: function ($scope, $elm, $attrs, uiGridCtrl) {

					}
				};
			}
		};
	}

	uiGridOperationRowHeaderButtons.$inject = ['$templateCache', 'uiGridSelectionService', 'gridUtil', '$timeout'];
	function uiGridOperationRowHeaderButtons($templateCache, uiGridSelectionService, gridUtil, $timeout) {
		return {
			replace: true,
			restrict: 'E',
			template: function ($elm, $attrs) {
				var isEolOprarion = $attrs.eol == undefined ? false : true;
				if (isEolOprarion) {
					return $templateCache.get('pti/eolOperationRowHeaderButtons');
				}
				return $templateCache.get('pti/operationRowHeaderButtons');
			},
			scope: true,
			require: '^uiGrid',
			link: function ($scope, $elm, $attrs, uiGridCtrl) {
				var self = uiGridCtrl.grid, watchers = [], watcher, authorization;
				var isEolOprarion = $attrs.eol == undefined ? false : true;
				$scope.$on('$destroy', function () {
					while (watchers.length) {
						(watchers.shift() || angular.noop)();
					}
				});
				$scope.disableElement = function ($event) {
					var btn = ($event.srcElement || $event.target).parentElement;
					if (btn.disabled) {
						return false;
					}
					btn.disabled = true;
					$timeout(function () {
						btn.disabled = false;
					}, 1000);
				};
				authorization = self.appScope ? (self.appScope.authorization || ((self.appScope.$stateParams) ? self.appScope.$stateParams.authorization : null)) : null;
				initFilterRowOperationCallBack();
				initViewButtonClickCallBack();
				initEditButtonClickCallBack();
				initCancelButtonClickCallBack();
				initDownloadButtonClickCallBack();
				initAddSubRowButtonClickCallBack();
				initRemoveButtonClickCallBack();
				initProcessButtonClickCallBack();
				function initFilterRowOperationCallBack() {
					if (self.options.filterRowOperation) {
						if (angular.isString(self.options.filterRowOperation)) {
							watcher = self.appScope.$watch(self.options.filterRowOperation, function (filterRowOperation) {
								$scope.filterRowOperation = function (row, operation) {
									if (angular.isFunction(filterRowOperation)) {
										return filterRowOperation(row, operation);
									} else {
										return false;
									}
								}
							});
							watchers.push(watcher);
						} else if (angular.isFunction(self.options.filterRowOperation)) {
							$scope.filterRowOperation = function (row, operation) {
								return self.options.filterRowOperation(row, operation);
							}
						} else {
							return false;
						}
					} else {
						$scope.filterRowOperation = function (row, operation) {
							return false;
						}
					}
				}

				function initViewButtonClickCallBack() {
					var viewPermission = isEolOprarion ? self.options.viewRowByEolPermission : self.options.viewRowPermission;
					$scope.viewPermission = {
						permission: viewPermission,
						authorization: authorization
					}
					var callback = isEolOprarion ? self.options.viewRowByEol : self.options.viewRow;
					if (callback && angular.isString(callback)) {
						$scope.viewButtonClick = angular.noop;
						watcher = self.appScope.$watch(callback, function (view) {
							$scope.viewButtonClick = function (row, $event) {
								(view || angular.noop)(row);
							};
						});
						watchers.push(watcher);
					} else if (angular.isFunction(callback)) {
						$scope.viewButtonClick = function (row, $event) {
							callback(row);
						};
					} else {
						$scope.viewButtonClick = angular.noop;
					}
				}

				function initEditButtonClickCallBack() {
					var editPermission = isEolOprarion ? self.options.editRowByEolPermission : self.options.editRowPermission;
					$scope.editPermission = {
						permission: editPermission,
						authorization: authorization
					}
					var callback = isEolOprarion ? self.options.editRowByEol : self.options.editRow;
					if (callback && angular.isString(callback)) {
						$scope.editButtonClick = angular.noop;
						watcher = self.appScope.$watch(callback, function (edit) {
							$scope.editButtonClick = function (row, $event) {
								(edit || angular.noop)(row);
							};
						});
						watchers.push(watcher);
					} else if (angular.isFunction(callback)) {
						$scope.editButtonClick = function (row, $event) {
							callback(row);
						};
					} else {
						$scope.editButtonClick = angular.noop;
					}
				}

				function initCancelButtonClickCallBack() {
					var cancelPermission = isEolOprarion ? self.options.cancelRowByEolPermission : self.options.cancelRowPermission;
					$scope.cancelPermission = {
						permission: cancelPermission,
						authorization: authorization
					}
					var callback = isEolOprarion ? self.options.cancelRowByEol : self.options.cancelRow;
					if (callback && angular.isString(callback)) {
						$scope.cancelButtonClick = angular.noop;
						watcher = self.appScope.$watch(callback, function (cancel) {
							$scope.cancelButtonClick = function (row, $event) {
								(cancel || angular.noop)(row);
							};
						});
						watchers.push(watcher);
					} else if (angular.isFunction(callback)) {
						$scope.cancelButtonClick = function (row, $event) {
							callback(row);
						};
					} else {
						$scope.cancelButtonClick = angular.noop;
					}
				}

				function initDownloadButtonClickCallBack() {
					var downloadPermission = isEolOprarion ? self.options.downloadRowByEolPermission : self.options.downloadRowPermission;
					$scope.downloadPermission = {
						permission: downloadPermission,
						authorization: authorization
					}
					var callback = isEolOprarion ? self.options.downloadRowByEol : self.options.downloadRow;
					if (callback && angular.isString(callback)) {
						$scope.downloadButtonClick = angular.noop;
						watcher = self.appScope.$watch(callback, function (download) {
							$scope.downloadButtonClick = function (row, $event) {
								(download || angular.noop)(row);
							};
						});
						watchers.push(watcher);
					} else if (angular.isFunction(callback)) {
						$scope.downloadButtonClick = function (row, $event) {
							callback(row);
						};
					} else {
						$scope.downloadButtonClick = angular.noop;
					}
				}

				function initAddSubRowButtonClickCallBack() {
					var addSubPermission = isEolOprarion ? self.options.addSubRowByEolPermission : self.options.addSubRowPermission;
					$scope.addSubPermission = {
						permission: addSubPermission,
						authorization: authorization
					}
					var callback = isEolOprarion ? self.options.addSubRowByEol : self.options.addSubRow;
					if (callback && angular.isString(callback)) {
						$scope.addSubRowButtonClick = angular.noop;
						watcher = self.appScope.$watch(callback, function (addSubRow) {
							$scope.addSubRowButtonClick = function (row, $event) {
								(addSubRow || angular.noop)(row);
							};
						});
						watchers.push(watcher);
					} else if (angular.isFunction(callback)) {
						$scope.addSubRowButtonClick = function (row, $event) {
							callback(row);
						};
					} else {
						$scope.addSubRowButtonClick = angular.noop;
					}
				}

				function initRemoveButtonClickCallBack() {
					var removePermission = isEolOprarion ? self.options.removeRowByEolPermission : self.options.removeRowPermission;
					$scope.removePermission = {
						permission: removePermission,
						authorization: authorization
					}
					var callback = isEolOprarion ? self.options.removeRowByEol : self.options.removeRow;
					if (callback && angular.isString(callback)) {
						$scope.removeButtonClick = angular.noop;
						watcher = self.appScope.$watch(callback, function (remove) {
							$scope.removeButtonClick = function (row, $event) {
								var promise = (remove || angular.noop)(row);
								if (promise && angular.isFunction(promise.then)) {
									promise.then(function () {
										removeRow(row, $event);
									});
								} else {
									removeRow(row, $event);
								}
								self.appScope.$emit('REMOVE_ROWS', [row]);
							};
						});
						watchers.push(watcher);
					} else if (angular.isFunction(callback)) {
						$scope.removeButtonClick = function (row, $event) {
							var promise = callback(row);
							if (promise && angular.isFunction(promise.then)) {
								promise.then(function () {
									removeRow(row, $event);
								});
							} else {
								removeRow(row, $event);
							}
							self.appScope.$emit('REMOVE_ROWS', [row]);
						};
					} else {
						$scope.removeButtonClick = function (row, $event) {
							removeRow(row, $event);
							self.appScope.$emit('REMOVE_ROWS', [row]);
						}
					}
				}

				function initProcessButtonClickCallBack() {
					var processPermission = isEolOprarion ? self.options.processRowByEolPermission : self.options.processRowPermission;
					$scope.processPermission = {
						permission: processPermission,
						authorization: authorization
					}
					var callback = isEolOprarion ? self.options.processRowByEol : self.options.processRow;
					if (callback && angular.isString(callback)) {
						$scope.processButtonClick = angular.noop;
						watcher = self.appScope.$watch(callback, function (process) {
							$scope.processButtonClick = function (row, $event) {
								(process || angular.noop)(row);
								self.appScope.$emit('REMOVE_ROWS', [row]);
							};
						});
						watchers.push(watcher);
					} else if (angular.isFunction(callback)) {
						$scope.processButtonClick = function (row, $event) {
							callback(row);
							self.appScope.$emit('REMOVE_ROWS', [row]);
						};
					} else {
						$scope.processButtonClick = function (row, $event) {
							self.appScope.$emit('REMOVE_ROWS', [row]);
						}
					}
				}
				$scope.moreProcessPermission = function (processConfig) {
					$scope.permission = {
						permission: processConfig.permission,
						authorization: authorization
					};
				};
				$scope.moreProcessClick = function (row, processConfig, $event) {
					var callback = processConfig.callback;
					if (callback && angular.isString(callback)) {
						callback = self.appScope.$eval(callback);
					}
					if (angular.isFunction(callback)) {
						callback(row);
					}
				};
				function removeRow(row, $event) {
					var selectedRows;
					if (row !== null && row.isSelected) {
						uiGridSelectionService.toggleRowSelection(self, row, $event, self.options.multiSelect, self.options.noUnselect);
					}
					removeItem(self.options.data, row.entity);
					selectedRows = getSelectedRows();
					if (selectedRows && selectedRows.length > 0 && selectedRows[0].isSelected) {
						uiGridSelectionService.toggleRowSelection(self, selectedRows[0], $event, self.options.multiSelect, self.options.noUnselect);
						$timeout(function () {
							uiGridSelectionService.toggleRowSelection(self, selectedRows[0], $event, self.options.multiSelect, self.options.noUnselect);
						});
					}
				}

				function getSelectedRows() {
					return self.rows.filter(function (row) {
						return row.isSelected;
					});
				}

				function removeItem(data, item) {
					var scope, items;
					if (angular.isString(self.options.data)) {
						if (self.options.data.match(/ngModel\..*/)) {
							scope = getNgModelScope($scope);
						} else {
							scope = self.appScope;
						}
						items = scope.$eval(self.options.data);
					} else {
						items = data;
					}
					angular.forEach(items, function (row, index) {
						if (self.options.rowEquality(row, item) || (row.primaryKey == item.primaryKey && item.primaryKey != undefined)) {
							if (!(row && row.dataStatus) || 'C' == row.dataStatus) {
								items.splice(index, 1);
							} else {
								items[index].dataStatus = 'D';
							}
						}
					});
				}

				function getNgModelScope(scope) {
					if (!scope) {
						return null;
					}
					if (scope.hasOwnProperty('ngModel')) {
						return scope;
					} else {
						return getNgModelScope(scope.$parent);
					}
				}
			}
		};
	}

	uiGridOperationHeaderButtons.$inject = ['$templateCache', '$timeout', 'uiGridGroupingService', 'uiGridSelectionService', 'modalService'];
	function uiGridOperationHeaderButtons($templateCache, $timeout, uiGridGroupingService, uiGridSelectionService, modalService) {
		return {
			replace: true,
			restrict: 'E',
			template: $templateCache.get('pti/operationHeaderButtons'),
			scope: true,
			link: function ($scope, $elm, $attrs, uiGridCtrl) {
				var self = $scope.col.grid;
				var watchers = [], watcher;
				$scope.$on('$destroy', function () {
					while (watchers.length) {
						(watchers.shift() || angular.noop)();
					}
				});
				if (self.options.addRow && angular.isString(self.options.addRow)) {
					$scope.addButtonClick = angular.noop;
					watcher = self.appScope.$watch(self.options.addRow, function (add) {
						$scope.addButtonClick = function ($event) {
							$scope.disableElement($event);
							var promise, row = { dataStatus: 'C' };
							if (!angular.isFunction(add)) {
								_addRow(self.options.data, row);
								return;
							}
							promise = (add || angular.noop)(row);
							if (promise && angular.isFunction(promise.then)) {
								promise.then(function () {
									_addRow(self.options.data, row);
								});
							} else {
								_addRow(self.options.data, row);
							}
							self.appScope.$emit('ADD_ROW', row);
						};
						self.options.__addRow = $scope.addButtonClick;
					});
					watchers.push(watcher);
				} else if (angular.isFunction(self.options.addRow)) {
					$scope.addButtonClick = function ($event) {
						$scope.disableElement($event);
						var row = { dataStatus: 'C' };
						var promise = self.options.addRow(row);
						if (promise && angular.isFunction(promise.then)) {
							promise.then(function () {
								_addRow(self.options.data, row);
							});
						} else {
							_addRow(self.options.data, row);
						}
						self.appScope.$emit('ADD_ROW', row);
					};
					self.options.__addRow = $scope.addButtonClick;
				} else {
					$scope.addButtonClick = function ($event) {
						$scope.disableElement($event);
						var row = { dataStatus: 'C' };
						_addRow(self.options.data, row);
						self.appScope.$emit('ADD_ROW', row);
					};
					self.options.__addRow = $scope.addButtonClick;
				}

				if (self.options.removeAllRows && angular.isString(self.options.removeAllRows)) {
					$scope.removeAllButtonClick = angular.noop;
					watcher = self.appScope.$watch(self.options.removeAllRows, function (removeAll) {
						$scope.removeAllButtonClick = function ($event) {
							var promise;
							if (!angular.isFunction(removeAll)) {
								removeAllRows($event);
								return;
							}
							promise = (removeAll || angular.noop)();
							if (promise && angular.isFunction(promise.then)) {
								promise.then(function () {
									removeAllRows($event);
								});
							} else {
								removeAllRows($event);
							}
							self.appScope.$emit('REMOVE_ROWS', getAllRows());
						};
					});
					watchers.push(watcher);
				} else if (angular.isFunction(self.options.removeAllRows)) {
					$scope.removeAllButtonClick = function ($event) {
						var promise;
						promise = self.options.removeAllRows();
						if (promise && angular.isFunction(promise.then)) {
							promise.then(function () {
								removeAllRows($event);
							});
						} else {
							removeAllRows($event);
						}
						self.appScope.$emit('REMOVE_ROWS', getAllRows());
					};
				} else {
					$scope.removeAllButtonClick = function ($event) {
						removeAllRows($event);
						self.appScope.$emit('REMOVE_ROWS', getAllRows());
					}
				}

				if (self.options.removeSelectedRows && angular.isString(self.options.removeSelectedRows)) {
					$scope.removeSelectedButtonClick = angular.noop;
					watcher = self.appScope.$watch(self.options.removeSelectedRows, function (removeSelected) {
						$scope.removeSelectedButtonClick = function ($event) {
							var promise, selectedRows = getSelectedRows();
							if (!selectedRows || selectedRows.length == 0) {
								modalService.openErrorDialogs({
									messages: ['title.dialogs.info.norecsel']
								});
								return false;
							}
							if (!angular.isFunction(removeSelected)) {
								removeSelectedRows($event);
								return;
							}
							promise = (removeSelected || angular.noop)();
							if (promise && angular.isFunction(promise.then)) {
								promise.then(function () {
									removeSelectedRows($event);
								});
							} else {
								removeSelectedRows($event);
							}
							self.appScope.$emit('REMOVE_ROWS', selectedRows);
						};
					});
					watchers.push(watcher);
				} else if (angular.isFunction(self.options.removeSelectedRows)) {
					$scope.removeSelectedButtonClick = function ($event) {
						var promise, selectedRows = getSelectedRows();
						if (!selectedRows || selectedRows.length == 0) {
							modalService.openErrorDialogs({
								messages: ['title.dialogs.info.norecsel']
							});
							return false;
						}
						promise = self.options.removeSelectedRows();
						if (promise && angular.isFunction(promise.then)) {
							promise.then(function () {
								removeSelectedRows($event);
							});
						} else {
							removeSelectedRows($event);
						}
						self.appScope.$emit('REMOVE_ROWS', selectedRows);
					};
				} else {
					$scope.removeSelectedButtonClick = function ($event) {
						var selectedRows = getSelectedRows();
						if (!selectedRows || selectedRows.length == 0) {
							modalService.openErrorDialogs({
								messages: ['title.dialogs.info.norecsel']
							});
							return false;
						}
						removeSelectedRows($event);
						self.appScope.$emit('REMOVE_ROWS', selectedRows);
					}
				}

				$scope.disableElement = function ($event) {
					var btn = ($event.srcElement || $event.target).parentElement;
					if (btn.disabled) {
						return false;
					}
					btn.disabled = true;
					$timeout(function () {
						btn.disabled = false;
					}, 1000);
				};

				function removeAllRows($event) {
					var rows = getAllRows();
					angular.forEach(rows, function (row) {
						if (row !== null && row.isSelected) {
							uiGridSelectionService.toggleRowSelection(self, row, $event, self.options.multiSelect, self.options.noUnselect);
						}
					});
					angular.forEach(rows, function (row) {
						removeItem(self.options.data, row.entity);
					});
					return rows;
				}

				function removeSelectedRows($event) {
					var selectedRows = getSelectedRows();
					angular.forEach(selectedRows, function (row) {
						if (row !== null && row.isSelected) {
							uiGridSelectionService.toggleRowSelection(self, row, $event, self.options.multiSelect, self.options.noUnselect);
						}
					});
					angular.forEach(selectedRows, function (selectedRow) {
						removeItem(self.options.data, selectedRow.entity);
					});
					return selectedRows;
				}

				function _addRow(data, row) {
					var scope;
					if (angular.isString(self.options.data)) {
						if (self.options.data.match(/ngModel\..*/)) {
							scope = getNgModelScope($scope);
						} else {
							scope = self.appScope;
						}
						data = scope.$eval(self.options.data);
					}
					data.push(row);
					sort(data, self);
					return row;
				}

				function sort(data, grid) {
					var columnSettings = uiGridGroupingService.getGrouping(grid);
					columnSettings.grouping.reverse();
					columnSettings.grouping.forEach(function (groupItem, index) {
						data.sort(function (a, b) {
							if (a[groupItem.field] != null && a[groupItem.field] != undefined) {
								return a[groupItem.field].localeCompare(b[groupItem.field]);
							} else if (b[groupItem.field] != null && b[groupItem.field] != undefined) {
								return -1;
							} else {
								return 0;
							}
						});
					});
				}

				function getSelectedRows() {
					if (self._selectedRows) {
						return self._selectedRows;
					} else {
						return self.rows.filter(function (row) {
							return row.isSelected;
						});
					}
				}

				function getAllRows() {
					return self.rows;
				}

				function removeItem(data, item) {
					var scope, items;
					if (angular.isString(self.options.data)) {
						if (self.options.data.match(/ngModel\..*/)) {
							scope = getNgModelScope($scope);
						} else {
							scope = self.appScope;
						}
						items = scope.$eval(self.options.data);
					} else {
						items = data;
					}
					angular.forEach(items, function (row, index) {
						if (self.options.rowEquality(row, item) || (row.primaryKey == item.primaryKey && item.primaryKey != undefined)) {
							if (!(row && row.dataStatus) || 'C' == row.dataStatus) {
								items.splice(index, 1);
							} else {
								items[index].dataStatus = 'D';
							}
						}
					});
				}
				function getNgModelScope(scope) {
					if (!scope) {
						return null;
					}
					if (scope.hasOwnProperty('ngModel')) {
						return scope;
					} else {
						return getNgModelScope(scope.$parent);
					}
				}
			}
		};
	}

	uiGridOperationTemplates.$inject = ['$templateCache', 'rowSorter'];
	function uiGridOperationTemplates($templateCache, rowSorter) {
		'use strict';
		if (!rowSorter.guessSortFnOveride) {
			rowSorter.guessSortFn = function guessSortFn(itemType) {
				switch (itemType) {
					case "number":
						return rowSorter.sortNumber;
					case "numberStr":
						return rowSorter.sortNumberStr;
					case "boolean":
						return rowSorter.sortBool;
					case "string":
						return rowSorter.sortAlpha;
					case "date":
						return rowSorter.sortDate;
					case "object":
						return rowSorter.basicSort;
					default:
						return rowSorter.sortAlpha;
				}
			};
			rowSorter.guessSortFnOveride = true;
		}
		$templateCache.put('fs/layout/template/uiGrid/tooltipTpl.html', ''
			+ '<ul class="fstooltip list-inline">\n'
			+ '   <li ng-repeat="message in (row.compareResult.fields[col.colDef.model].tooltip || col.colDef.tooltip)">{{message | translate }}</li>\n'
			+ '</ul>\n'
		);

		$templateCache.put('fs-grid/uiGridCell/tooltip', ''
			+ '<ul class="list-inline">\n'
			+ '    <li ng-repeat="message in tooltipMessage"><span>{{ message | translate }}</span>\n'
			+ '</ul>\n'
		);


		$templateCache.put('pti/operationRowHeader', ''
			+ '<div class="ui-grid-disable-operation">'
			+ '    <div class="ui-grid-cell-contents operationRowHeader">'
			+ '        <ui-grid-operation-row-header-buttons></ui-grid-operation-row-header-buttons>'
			+ '    </div>'
			+ '</div>');

		$templateCache.put('pti/operationRowHeaderButtons', ''
			+ '<div class="operationRowHeaderButtons">'
			+ '    <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableOperationView && !(filterRowOperation(row, \'view\') == true)" ng-click="viewRowTooltipIsOpen=false;disableElement($event);viewButtonClick(row, $event)"'
			+ '         tooltip-is-open="viewRowTooltipIsOpen" uib-tooltip="{{\'label.global.view\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-view"></span>'
			+ '    </button>'
			+ '    <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableOperationEdit && !(filterRowOperation(row, \'edit\') == true)" ng-click="editRowTooltipIsOpen=false;disableElement($event);editButtonClick(row, $event)"'
			+ '         tooltip-is-open="editRowTooltipIsOpen" uib-tooltip="{{\'label.global.edit\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-edit"></span>'
			+ '    </button>'
			+ '    <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableOperationAddSubRow && !(filterRowOperation(row, \'add\') == true)" ng-click="addSubRowTooltipIsOpen=false;disableElement($event);addSubRowButtonClick(row, $event)"'
			+ '        tooltip-is-open="addSubRowTooltipIsOpen" uib-tooltip="{{\'label.global.addsubrow\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-add_1"></span>'
			+ '    </button>'
			+ '    <button type="button" class="btn btn-default btn-xs" ng-show="!grid.options.enableRowHeaderSelection && grid.options.enableOperationRemove && !(filterRowOperation(row, \'remove\') == true)" ng-click="removeRowTooltipIsOpen=false;disableElement($event);removeButtonClick(row, $event)"'
			+ '        tooltip-is-open="removeRowTooltipIsOpen" uib-tooltip="{{\'label.global.remove\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-delete_1"></span>'
			+ '    </button>'
			+ '    <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableOperationProcess && !(filterRowOperation(row, \'process\') == true)" ng-click="processRowTooltipIsOpen=false;disableElement($event);processButtonClick(row, $event)"'
			+ '        tooltip-is-open="processRowTooltipIsOpen" uib-tooltip="{{\'label.global.process\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-play"></span>'
			+ '    </button>'
			+ '    <div uib-dropdown dropdown-append-to-body="\'true\'" ng-show="grid.options.enableOperationMoreProcess && !(filterRowOperation(row, \'more\') == true)" style="display:inline-block">'
			+ '      <button uib-dropdown-toggle type="button" class="btn btn-default btn-xs" ng-click="moreProcessRowTooltipIsOpen=false;disableElement($event);moreProcessButtonClick(row, $event)"'
			+ '        tooltip-is-open="moreProcessRowTooltipIsOpen" uib-tooltip="{{grid.options.moreProcess.tooltip || \'label.global.processmore\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.moreProcess.icon || \'more\'}}"></span>'
			+ '      </button>'
			+ '      <ul class="animated fadeInUp dropdown-menu-right" uib-dropdown-menu>'
			+ '        <li ng-repeat="processConfig in grid.options.moreProcess.items" fs-permission="permission" ng-init="moreProcessPermission(processConfig)" ng-show="!(filterRowOperation(row, processConfig.name) == true)"><a href="#" ng-click="moreProcessClick(row, $event)"><i class="icon icon-{{processConfig.icon}}"></i><span>{{processConfig.label|translate}}</span></a></li>'
			+ '      </ul>'
			+ '    <div>'
			+ '</div>');

		$templateCache.put('pti/eolOperationRowHeader', ''
			+ '<div class="ui-grid-disable-operation">'
			+ '    <div class="ui-grid-cell-contents operationRowHeader">'
			+ '        <ui-grid-operation-row-header-buttons eol></ui-grid-operation-row-header-buttons>'
			+ '    </div>'
			+ '</div>');

		$templateCache.put('pti/eolOperationRowHeaderButtons', ''
			+ '<div class="operationRowHeaderButtons">'
			+ '    <button type="button" fs-permission="viewPermission" class="btn btn-default btn-xs" ng-show="grid.options.enableEolOperationView && !(filterRowOperation(row, \'view\') == true)" ng-click="viewRowTooltipIsOpen=false;disableElement($event);viewButtonClick(row, $event)"'
			+ '         tooltip-is-open="viewRowTooltipIsOpen" uib-tooltip="{{grid.options.viewRowByEol.tooltip || (\'label.global.view\'|translate)}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.viewRowByEol.icon || \'view\'}}"></span>'
			+ '    </button>'
			+ '    <button type="button" fs-permission="editPermission" class="btn btn-default btn-xs" ng-show="grid.options.enableEolOperationEdit && !(filterRowOperation(row, \'edit\') == true)" ng-click="editRowTooltipIsOpen=false;disableElement($event);editButtonClick(row, $event)"'
			+ '         tooltip-is-open="editRowTooltipIsOpen" uib-tooltip="{{grid.options.editRowByEol.tooltip || (\'label.global.edit\'|translate)}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.editRowByEol.icon || \'edit\'}}"></span>'
			+ '    </button>'
			+ '    <button type="button" fs-permission="cancelPermission" class="btn btn-default btn-xs" ng-show="grid.options.enableEolOperationCancel && !(filterRowOperation(row, \'cancel\') == true)" ng-click="cancelRowTooltipIsOpen=false;disableElement($event);cancelButtonClick(row, $event)"'
			+ '         tooltip-is-open="cancelRowTooltipIsOpen" uib-tooltip="{{grid.options.cancelRowByEol.tooltip || (\'label.global.cancel\'|translate)}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.cancelRowByEol.icon || \'cancel\'}}"></span>'
			+ '    </button>'
			+ '    <button type="button" fs-permission="downloadPermission" class="btn btn-default btn-xs" ng-show="grid.options.enableEolOperationDownload && !(filterRowOperation(row, \'download\') == true)" ng-click="downloadRowTooltipIsOpen=false;disableElement($event);downloadButtonClick(row, $event)"'
			+ '         tooltip-is-open="downloadRowTooltipIsOpen" uib-tooltip="{{grid.options.downloadRowByEol.tooltip || (\'label.global.download\'|translate)}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.downloadRowByEol.icon || \'download\'}}"></span>'
			+ '    </button>'
			+ '    <button type="button" fs-permission="addSubPermission" class="btn btn-default btn-xs" ng-show="grid.options.enableEolOperationAddSubRow && !(filterRowOperation(row, \'add\') == true)" ng-click="addSubRowTooltipIsOpen=false;disableElement($event);addSubRowButtonClick(row, $event)"'
			+ '        tooltip-is-open="addSubRowTooltipIsOpen" uib-tooltip="{{grid.options.addSubRowByEol.tooltip || (\'label.global.addsubrow\'|translate)}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.addSubRowByEol.icon || \'add_1\'}}"></span>'
			+ '    </button>'
			+ '    <button type="button" fs-permission="removePermission" class="btn btn-default btn-xs" ng-show="!grid.options.enableRowHeaderSelection && grid.options.enableEolOperationRemove && !(filterRowOperation(row, \'remove\') == true)" ng-click="removeRowTooltipIsOpen=false;disableElement($event);removeButtonClick(row, $event)"'
			+ '        tooltip-is-open="removeRowTooltipIsOpen" uib-tooltip="{{grid.options.removeRowByEol.tooltip || (\'label.global.remove\'|translate)}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.removeRowByEol.icon || \'remove\'}}"></span>'
			+ '    </button>'
			+ '    <button type="button" fs-permission="processPermission" class="btn btn-default btn-xs" ng-show="grid.options.enableEolOperationProcess && !(filterRowOperation(row, \'process\') == true)" ng-click="processRowTooltipIsOpen=false;disableElement($event);processButtonClick(row, $event)"'
			+ '        tooltip-is-open="processRowTooltipIsOpen" uib-tooltip="{{grid.options.processRowByEol.tooltip || (\'label.global.process\'|translate)}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.processRowByEol.icon || \'play\'}}"></span>'
			+ '    </button>'
			+ '    <div uib-dropdown dropdown-append-to-body="\'true\'" ng-show="grid.options.enableEolOperationMoreProcess && !(filterRowOperation(row, \'more\') == true)" style="display:inline-block">'
			+ '      <button uib-dropdown-toggle type="button" class="btn btn-default btn-xs" ng-click="moreProcessRowTooltipIsOpen=false;disableElement($event);moreProcessButtonClick(row, $event)"'
			+ '        tooltip-is-open="moreProcessRowTooltipIsOpen" uib-tooltip="{{grid.options.moreProcessByEol.tooltip || \'label.global.processmore\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-{{grid.options.moreProcessByEol.icon || \'more\'}}"></span>'
			+ '      </button>'
			+ '      <ul class="animated fadeInUp dropdown-menu-right" uib-dropdown-menu>'
			+ '        <li ng-repeat="processConfig in grid.options.moreProcessByEol.items" fs-permission="moreProcessPermission(processConfig)" ng-show="!(filterRowOperation(row, processConfig.name) == true)"><a href="#" ng-click="moreProcessClick(row, processConfig, $event)"><i class="icon icon-{{processConfig.icon}}"></i><span>{{processConfig.label|translate}}</span></a></li>'
			+ '      </ul>'
			+ '    <div>'
			+ '</div>');

		$templateCache.put('pti/operationHeaderCell', ''
			+ '<div class="operationHeaderCell">'
			+ '    <div class="ui-grid-cell-contents operationHeaderCell" col-index="renderIndex">'
			+ '        <ui-grid-operation-header-buttons></ui-grid-operation-add-button>'
			+ '    </div>'
			+ '</div>');

		$templateCache.put('pti/operationHeaderButtons', ''
			+ '<div class="operationHeaderButtons">'
			//		+ '    <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableOperationAdd" ng-click="addTooltipIsOpen=false;disableElement($event);addButtonClick($event)"'
			//		+ '        tooltip-is-open="addTooltipIsOpen" uib-tooltip="{{\'label.global.add\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			//		+ '    	   <span class="icon icon-add_1"></span>'
			//		+ '    </button>'
			+ '    <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableOperationRemoveAll" ng-click="removeAllTooltipIsOpen=false;disableElement($event);removeAllButtonClick($event)"'
			+ '        tooltip-is-open="removeAllTooltipIsOpen" uib-tooltip="{{\'label.global.removeselected\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-delete_1"></span>'
			+ '    </button>'
			+ '    <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableRowHeaderSelection && grid.options.enableOperationRemoveSelected" ng-click="removeTooltipIsOpen=false;disableElement($event);removeSelectedButtonClick($event)"'
			+ '        tooltip-is-open="removeTooltipIsOpen" uib-tooltip="{{\'label.global.removeselected\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	   <span class="icon icon-delete_1"></span>'
			+ '    </button>'
			+ '</div>');

		$templateCache.put('ui-grid/ui-grid-grid-footer',
			"<div class=\"ui-grid-footer-info ui-grid-grid-footer\"><span>{{\"label.pagination.totalitems\"|translate}}: {{grid.options.total}}</span> <span ng-if=\"grid.renderContainers.body.visibleRowCache.length !== grid.rows.length\" class=\"ngLabel\">({{\"search.showingItems\" | t}} {{grid.renderContainers.body.visibleRowCache.length}})</span></div>"
		);

		$templateCache.put('ui-grid/gridFooterSelectedItems',
			"<span ng-if=\"grid.selection.selectedCount !== 0 && grid.options.enableFooterTotalSelected\">({{\"label.pagination.selecteditems\"|translate}}: {{grid.selection.selectedCount}})</span>"
		);

		$templateCache.put('ui-grid/pagination', ''
			+ '<div role="contentinfo" class="ui-grid-pager-panel paginationBar clearfix" ui-grid-pager ng-if="grid.options.enablePaginationControls">'
			+ '    <ul class="pull-right" uib-pagination template-url="ui-grid/pagination/pagination.html" items-per-page="grid.options.paginationPageSize" total-items="grid.options.totalItems" ng-model="grid.options.paginationCurrentPage" boundary-links="true" first-text="<<" previous-text="<" next-text=">" last-text=">>"></ul>'
			+ '    <div class="pagination ui-grid-pager-row-count-picker pull-right" ng-if="grid.options.paginationPageSizes.length > 1 && !grid.options.useCustomPagination">'
			+ '       <label> {{"label.pagination.go"|translate}} </label> <input type="number" onclick="this.focus()" class="form-control input-sm btn-xs" ui-grid-one-bind-title="aria.pageSelected" ui-grid-one-bind-aria-label="aria.pageSelected" class="ui-grid-pager-control-input" ng-model="grid.options.paginationCurrentPage" ng-keydown="grid.options.pageNumKeydown()" ng-model-options="{ updateOn: \'blur\' }" style="width:60px" min="1" max="{{ paginationApi.getTotalPages() }}" required>'
			+ '       <span class="ui-grid-pager-max-pages-number" ng-show="paginationApi.getTotalPages() > 0">/ {{ paginationApi.getTotalPages() }}</span>'
			+ '    </div>'
			+ '    <div class="pagination ui-grid-pager-row-count-picker pull-right" ng-if="grid.options.paginationPageSizes.length > 1 && !grid.options.useCustomPagination">'
			+ '       <label style="padding-right:8px;">{{grid.options.totalItems}} {{\"label.pagination.totalitems\"|translate}} </label>  <label> {{"label.pagination.pagesize"|translate}} </label> <select class="form-control input-sm btn-xs" ui-grid-one-bind-aria-labelledby-grid="\'items-per-page-label\'" ng-model="grid.options.paginationPageSize" ng-options="o as o for o in grid.options.paginationPageSizes"></select>'
			+ '    </div>'
			+ '</div>'
		);

		$templateCache.put('ui-grid/pagination/pagination.html', ''
			+ '<li ng-if="::boundaryLinks" ng-class="{disabled: noPrevious()||ngDisabled}" class="pagination-first"><a href ng-click="selectPage(1, $event)" ng-disabled="noPrevious()||ngDisabled" uib-tabindex-toggle><span class="icon icon-firstpage"></span></a></li>\n'
			+ '<li ng-if="::directionLinks" ng-class="{disabled: noPrevious()||ngDisabled}" class="pagination-prev"><a href ng-click="selectPage(page - 1, $event)" ng-disabled="noPrevious()||ngDisabled" uib-tabindex-toggle><span class="icon icon-page-left"></span></a></li>\n'
			+ '<li ng-if="page > 6" class="pagination-page disabled"><a href uib-tabindex-toggle>...</a></li>\n'
			+ '<li ng-repeat="pageItem in pages track by $index" ng-class="{active: pageItem.active,disabled: ngDisabled&&!pageItem.active}" class="pagination-page">'
			+ '  <a href ng-click="selectPage(pageItem.number, $event)" ng-if="(pageItem.number <= page + 5) && (pageItem.number >= page - 5)" ng-disabled="ngDisabled&&!pageItem.active" uib-tabindex-toggle>{{pageItem.text}}</a>'
			+ '</li>\n'
			+ '<li ng-if="page < pages.length - 5" class="pagination-page disabled"><a href uib-tabindex-toggle>...</a></li>\n'
			+ '<li ng-if="::directionLinks" ng-class="{disabled: noNext()||ngDisabled}" class="pagination-next"><a href ng-click="selectPage(page + 1, $event)" ng-disabled="noNext()||ngDisabled" uib-tabindex-toggle><span class="icon icon-page-right"></span></a></li>\n'
			+ '<li ng-if="::boundaryLinks" ng-class="{disabled: noNext()||ngDisabled}" class="pagination-last"><a href ng-click="selectPage(totalPages, $event)" ng-disabled="noNext()||ngDisabled" uib-tabindex-toggle><span class="icon icon-lastpage"></span></a></li>\n'
		);

		$templateCache.put('ui-grid/selectionRowHeaderButtons', ''
			+ '<div class="selectionRowHeaderButtons">'
			+ '    <input class="rowHeader" type="{{grid.options.multiSelect ? \'checkbox\' : \'radio\'}}" id="{{grid.id}}" ng-if="!row.groupHeader" ng-disabled="!grid.options.isRowSelectable(row)" ng-checked="row.isSelected" ng-click="selectButtonClick(row, $event)"><label ng-if="!row.groupHeader" for="{{row.uid}}">&nbsp;</label>'
			+ '</div>'
		);

		$templateCache.put('ui-grid/selectionSelectAllButtons', ''
			+ '<div class="selectionSelectAllButtons">'
			+ '    <input type="checkbox" id="{{grid.id}}" ng-show="grid.options.multiSelect" ng-checked="grid.selection.selectAll" ng-click="headerButtonClick($event)"><label ng-show="grid.options.multiSelect" for="{{grid.id}}">&nbsp;</label>'
			+ '</div>'
		);

		$templateCache.put('ui-grid/ui-grid-header', ""
			+ "<div role=\"rowgroup\" class=\"ui-grid-header\">\n"
			+ " <!-- theader -->\n"
			+ " <div class=\"ui-grid-top-panel\">\n"
			+ "   <div class=\"ui-grid-header-viewport\">\n"
			+ "     <div class=\"ui-grid-header-canvas\">\n"
			+ "       <div class=\"ui-grid-header-cell-wrapper\" ng-style=\"colContainer.headerCellWrapperStyle()\">\n"
			+ "         <div role=\"row\" class=\"ui-grid-header-cell-row\">\n"
			+ "           <div class=\"ui-grid-header-cell ui-grid-clearfix\" ng-mouseover=\"col.colDef._hover=true\" ng-mouseleave=\"col.colDef._hover=false\" ng-class=\"{'hover': col.colDef._hover}\" ng-repeat=\"col in colContainer.renderedColumns track by col.uid\" ui-grid-header-cell col=\"col\" render-index=\"$index\"></div>\n"
			+ "           </div>\n"
			+ "         </div>\n"
			+ "       </div>\n"
			+ "   </div>\n"
			+ " </div>\n"
			+ "</div>");

		$templateCache.put('ui-grid/uiGridHeaderCell', ""
			+ "<div role=\"columnheader\" ng-class=\"{ 'sortable': sortable, 'ui-grid-header-cell-last-col': isLastCol }\" aria-sort=\"{{col.sort.direction == asc ? 'ascending' : ( col.sort.direction == desc ? 'descending' : (!col.sort.direction ? 'none' : 'other'))}}\">\n"
			+ "    <div role=\"button\" tabindex=\"0\" ng-keydown=\"handleKeyDown($event)\" ng-mouseover=\"col.colDef._hover=true\" ng-mouseleave=\"col.colDef._hover=false\" ng-class=\"{'text-right':col.colDef.textAlign == 'right', 'text-left':col.colDef.textAlign == 'left', 'text-center':col.colDef.textAlign == 'center', 'hover': col.colDef._hover}\" class=\"ui-grid-cell-contents ui-grid-header-cell-primary-focus\" col-index=\"renderIndex\" title=\"TOOLTIP\">\n"
			+ "        <span ui-grid-one-bind-id-grid=\"col.uid + '-header-text'\">\n"
			+ "            <span ng-if=\"col.colDef.isRequired\" ng-class=\"{required: col.colDef.isRequired}\" style=\"padding-right:2px\"></span> <span>{{ col.displayName CUSTOM_FILTERS }}</span>\n"
			+ "        </span>\n"
			+ "    </div>\n"
			+ "    <div style=\"top: 0; width: 16px; position: absolute; right: 0; line-height: 6px;padding-top: 8px;\" ng-if=\"col.sort.direction\">\n"
			+ "         <i class=\"icon icon-up_1\" ng-class=\"{ 'active': col.sort.direction == asc, 'disable': !col.sort.direction }\" aria-hidden=\"true\"></i> \n"
			+ "         <i class=\"icon icon-down_1\" ng-class=\"{ 'active': col.sort.direction == desc, 'disable': !col.sort.direction }\" aria-hidden=\"true\"></i> \n"
			+ "    </div>\n"
			+ "    <div role=\"button\" tabindex=\"0\" ui-grid-one-bind-id-grid=\"col.uid + '-menu-button'\" class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader  && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-keydown=\"headerCellArrowKeyDown($event)\" ui-grid-one-bind-aria-label=\"i18n.headerCell.aria.columnMenuButtonLabel\" aria-haspopup=\"true\">\n"
			+ "        <i class=\"ui-grid-icon-angle-down\" aria-hidden=\"true\">&nbsp;</i>\n"
			+ "    </div>\n"
			+ "    <div ui-grid-filter></div>\n"
			+ "</div>"
		);

		$templateCache.put('ui-grid/uiGridViewport', ''
			+ '<div role="rowgroup" class="ui-grid-viewport" ng-style="colContainer.getViewportStyle()">\n'
			+ '<div ui-grid-customer-scrollbar on-scroll="scrollHandler" refresh-on-change="rowContainer.renderedRows" wheel-propagation="true" class="scroller">\n'
			+ "    <!-- tbody -->\n"
			+ '    <div class="ui-grid-canvas">\n'
			+ '        <div ng-form="rowForm{{side ? rowRenderIndex : \'Entity\'+rowRenderIndex}}" ng-repeat="(rowRenderIndex, row) in rowContainer.renderedRows" class="ui-grid-row" ng-style="Viewport.rowStyle(rowRenderIndex)">'
			+ '            <div role="row" class="grid-row" ui-grid-row="row" ng-mouseover="row._hover=true" ng-mouseleave="row._hover=false"'
			+ '                ng-class="{\'selected-row\':row.isSelected,'
			+ '                           \'hover-row\':row._hover, '
			+ '                           \'created-row\':row.compareResult.isCreated,'
			+ '                           \'deleted-row\':row.compareResult.isDeleted,'
			+ '                           \'updated-row\':row.compareResult.isUpdated}" row-render-index="rowRenderIndex" '
			+ '                fs-ui-grid-compare="row.grid.options.verifyData" fs-ui-grid="grid" fs-ui-grid-row="row" fs-ui-grid-col="col"></div>'
			+ '         </div>'
			+ '    </div>'
			+ '</div>'
			+ '</div>'
		);

		$templateCache.put('ui-grid/uiGridCell', ''
			+ '<div class="ui-grid-cell-contents" ng-class="{\'updated-cell\': row.compareResult.fields[col.colDef.model].hasChanged}" title="TOOLTIP"'
			+ '  ng-style="{\'text-align\':col.colDef.textAlign || \'left\'}"'
			+ '  uib-tooltip-template="\'fs/layout/template/uiGrid/tooltipTpl.html\'"'
			+ '  tooltip-enable="(row.compareResult.columns[col.colDef.model].tooltipMessage && row.compareResult.columns[col.colDef.model].tooltipMessage.length > 0) || (col.colDef.tooltip && col.colDef.tooltip.length > 0)"'
			+ '  tooltip-class="{{col.colDef.tooltipClass}}" '
			+ '  tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="true" '
			+ '  tooltip-placement="{{col.colDef.tooltipPlacement}}">'
			+ '    <span>{{COL_FIELD CUSTOM_FILTERS}}</span>'
			+ ' </div>'
		);

		$templateCache.put('ui-grid/ui-grid', ""
			+ "<div ui-i18n=\"en\" class=\"ui-grid\" ng-class=\"{'enable-grid-menu':grid.options.enableGridMenu}\"><!-- TODO (c0bra): add \"scoped\" attr here, eventually? -->\n"
			+ "    <style ui-grid-style>\n"
			+ "    .grid{{ grid.id }} {\n"
			+ "        /* Styles for the grid */\n"
			+ "    }\n" +
			+ "    .grid{{ grid.id }} .ui-grid-row, \n"
			+ "    .grid{{ grid.id }} .ui-grid-cell, \n"
			+ "    .grid{{ grid.id }} .ui-grid-cell .ui-grid-vertical-bar {\n"
			+ "        min-height: {{ grid.options.rowHeight }}px;\n"
			+ "    }\n"
			+ "    .grid{{ grid.id }} .ui-grid-row:last-child .ui-grid-cell {\n"
			+ "        border-bottom-width: {{ (((grid.getVisibleRowCount() * grid.options.rowHeight) < grid.getViewportHeight()) && '1px') || '0' }};\n"
			+ "    }\n"
			+ "\n"
			+ "    {{ grid.verticalScrollbarStyles }}\n"
			+ "    {{ grid.horizontalScrollbarStyles }}\n"
			+ "\n"
			+ "    /*\n"
			+ "    .ui-grid[dir=rtl] .ui-grid-viewport {\n"
			+ "        padding-left: {{ grid.verticalScrollbarWidth }}px;\n"
			+ "    }\n"
			+ "    */\n"
			+ "    \n"
			+ "    {{ grid.customStyles }}\n"
			+ "\n"
			+ "    </style>\n"
			+ "    <div class=\"ui-grid-contents-wrapper\" role=\"grid\">\n"
			+ "        <div ui-grid-menu-customer-button ng-if=\"grid.options.enableGridMenu\"></div>\n"
			+ "        <div ng-if=\"grid.hasLeftContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'left'\" class=\"oprationContainer\"></div>\n"
			+ "        <div ui-grid-render-container container-id=\"'body'\" col-container-name=\"'body'\" row-container-name=\"'body'\" bind-scroll-horizontal=\"true\" bind-scroll-vertical=\"true\"\n"
			+ "            enable-horizontal-scrollbar=\"grid.options.enableHorizontalScrollbar\" \n"
			+ "            enable-vertical-scrollbar=\"grid.options.enableVerticalScrollbar\"></div>\n"
			+ "        <div ng-if=\"grid.hasRightContainer()\" style=\"width: 0\" ui-grid-pinned-container=\"'right'\" class=\"oprationContainer\"></div>\n"
			+ "        <div ui-grid-grid-footer ng-if=\"grid.options.showGridFooter\" class=\"gridFooterbox clearfix\"></div>\n"
			+ "        <div ui-grid-column-menu ng-if=\"grid.options.enableColumnMenus\" style=\"z-index:1000\"></div>\n"
			+ "        <div ng-transclude></div>\n"
			+ "    </div>\n"
			+ "</div>"
		);

		$templateCache.put('ui-grid/ui-grid-menu-button', ""
			+ "<div class=\"ui-grid-menu-button\">\n"
			+ "  <div class=\"media\">\n"
			+ "    <div class=\"switch media-body media-middle\">"
			+ "      <input type=\"checkbox\" id=\"switch{{grid.id}}\" ng-model=\"switchChecked\" class=\"switch-checkbox\" ng-checked=\"grid.options.displayStyle == 'all'\" ng-click=\"toggleDisplayStyle()\">"
			+ "      <label class=\"switch-label\" for=\"switch{{grid.id}}\">"
			+ "        <span class=\"switch-inner\" data-all=\"{{'grid.label.showall' | translate}}\" data-normal=\"{{'grid.label.normal' | translate}}\"></span>"
			+ "        <span class=\"switch-icon\"></span>"
			+ "      </label>"
			+ "    </div>"
			+ "    <div role=\"button\" ui-grid-one-bind-id-grid=\"'grid-menu'\" class=\"ui-grid-icon-container media-right media-middle\" ng-click=\"toggleMenu()\" aria-haspopup=\"true\">\n"
			+ "        <i class=\"ui-grid-icon-menu\"></i>\n"
			+ "    </div>\n"
			+ "  </div>"
			+ "  <div ui-grid-menu menu-items=\"menuItems\"></div>\n"
			+ "</div>"
		);

		$templateCache.put('ui-grid/uiGridMenu', ""
			+ "<div class=\"ui-grid-menu\" ng-show=\"shown\">\n"
			/*+ "    <style ui-grid-style>{{dynamicStyles}}</style>\n"*/
			+ "    <div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\">\n"
			+ "        <div class=\"ui-grid-menu-inner\" ng-if=\"shown\">\n"
			+ "            <ul role=\"menu\" class=\"ui-grid-menu-items\">\n"
			+ "                <li><h4>{{'grid.label.customize'|translate}}:</h4></li>\n"
			+ "                <li ng-repeat=\"item in menuItems\" ng-click=\"$event.stopPropagation();\" ng-if=\"item.context && item.context.gridCol\" role=\"menuitem\" ui-grid-customer-menu-item ui-grid-one-bind-id=\"'menuitem-'+$index\"action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\" leave-open=\"item.leaveOpen\" index=\"$index\" screen-reader-only=\"item.screenReaderOnly\"></li>\n"
			+ "            </ul>\n"
			+ "        </div>\n"
			+ "    </div>\n"
			+ "</div>"
		);


		$templateCache.put('ui-grid/uiGridMenuItem', ""
			+ "<div class=\"ui-grid-menu-item\" ng-focus=\"focus=true\" ng-blur=\"focus=false\" ng-show=\"itemShown() && action\">\n"
			+ "    <input id=\"{{getGrid().id+''+index}}\" type=\"checkbox\" ng-model=\"visible\" ng-click=\"itemAction($event, title)\" ng-checked=\"visible != false\"/>"
			+ "     <label for=\"{{getGrid().id+''+index}}\" style=\"cursor: pointer;\" >{{ label() }}</label>"
			+ "</div>"
		);

		$templateCache.put('ui-grid/uiGridRenderContainer', ""
			+ "<div role=\"presentation\" ui-grid-one-bind-id-grid=\"'grid-container'\" class=\"ui-grid-render-container\" ng-style=\"{ 'margin-left': colContainer.getMargin('left') + 'px', 'margin-right': colContainer.getMargin('right') + 'px' }\">\n"
			+ "    <!-- All of these dom elements are replaced in place -->\n"
			+ "    <div ui-grid-header></div>\n"
			+ "    <div ui-grid-viewport></div>\n"
			+ "    <div ng-if=\"colContainer.needsHScrollbarPlaceholder()\" class=\"ui-grid-scrollbar-placeholder\" ng-style=\"{height:colContainer.grid.scrollbarHeight + 'px'}\"></div>\n"
			+ "    <ui-grid-footer ng-if=\"grid.options.showColumnFooter\"></ui-grid-footer>\n"
			+ "</div>");

		$templateCache.put('ui-grid/ui-grid-footer', ""
			+ "<div class=\"ui-grid-footer-panel ui-grid-footer-aggregates-row\">\n"
			+ "    <!-- tfooter -->\n"
			+ "    <div class=\"ui-grid-footer ui-grid-footer-viewport\">\n"
			+ "        <div class=\"ui-grid-footer-canvas\">\n"
			+ "            <div class=\"ui-grid-footer-cell-wrapper\" ng-style=\"colContainer.headerCellWrapperStyle()\">\n"
			+ "                <div role=\"row\" class=\"ui-grid-footer-cell-row\">\n"
			+ "                    <div role=\"gridcell\" ng-repeat=\"col in colContainer.renderedColumns track by col.uid\" col=\"col\" render-index=\"$index\" class=\"ui-grid-footer-cell ui-grid-clearfix\">\n"
			+ "                        <div class=\"operationHeaderButtons\" ng-if=\"col.colDef.name == 'operationRowHeaderCol' && col.grid.options.__addRow\">\n"
			+ '                            <button type="button" class="btn btn-default btn-xs" ng-show="grid.options.enableOperationAdd" ng-click="addTooltipIsOpen=false;col.grid.options.__addRow($event)"'
			+ '                                tooltip-is-open="addTooltipIsOpen" uib-tooltip="{{\'label.global.add\'|translate}}" tooltip-append-to-body="true" tooltip-trigger="\'mouseenter\'" tooltip-append-to-body="false" tooltip-placement="top">'
			+ '    	                           <span class="icon icon-add_1"></span>'
			+ '                            </button>'
			+ "                         </div>"
			+ "                    </div>\n"
			+ "                </div>\n"
			+ "            </div>\n"
			+ "        </div>\n"
			+ "    </div>\n"
			+ "</div>"
		);

		$templateCache.put('ui-grid/emptyBaseLayerContainer', '');

		$templateCache.put('ui-grid/columnResizer',
			"<div ui-grid-customer-column-resizer ng-if=\"grid.options.enableColumnResizing && !grid.options.disableColumnResize\" class=\"ui-grid-column-resizer\" col=\"col\" position=\"right\" render-index=\"renderIndex\" unselectable=\"on\"></div>"
		);

		/*
		 * $templateCache.put('ui-grid/ui-grid-header', "" + "<div role=\"rowgroup\" class=\"ui-grid-header\">\n" + " <!-- theader -->\n" + " <div class=\"ui-grid-top-panel\">\n" + " <div
		 * class=\"ui-grid-header-viewport\">\n" + " <div class=\"ui-grid-header-canvas\">\n" + " <div class=\"ui-grid-header-cell-wrapper\" ng-style=\"colContainer.headerCellWrapperStyle()\">\n" + " <div
		 * role=\"row\" class=\"ui-grid-header-cell-row\">\n" + " <div class=\"ui-grid-header-cell ui-grid-clearfix\" ng-repeat=\"col in colContainer.renderedColumns track by col.uid\" ui-grid-header-cell
		 * col=\"col\" render-index=\"$index\"></div>\n" + " </div>\n" + " </div>\n" + " </div>\n" + " </div>\n" + " </div>\n" + "</div>" );
		 * 
		 * $templateCache.put('ui-grid/uiGridHeaderCell', "" + "<div role=\"columnheader\" ng-class=\"{ 'sortable': sortable, 'ui-grid-header-cell-last-col': isLastCol }\"
		 * ui-grid-one-bind-aria-labelledby-grid=\"col.uid + '-header-text ' + col.uid + '-sortdir-text'\" aria-sort=\"{{col.sort.direction == asc ? 'ascending' : ( col.sort.direction == desc ?
		 * 'descending' : (!col.sort.direction ? 'none' : 'other'))}}\">\n" + " <div role=\"button\" tabindex=\"0\" ng-keydown=\"handleKeyDown($event)\" class=\"ui-grid-cell-contents
		 * ui-grid-header-cell-primary-focus\" col-index=\"renderIndex\" title=\"TOOLTIP\">\n" + " <span class=\"ui-grid-header-cell-label\" ui-grid-one-bind-id-grid=\"col.uid + '-header-text'\">{{
		 * col.displayName CUSTOM_FILTERS }}</span> \n" + " <span ui-grid-one-bind-id-grid=\"col.uid + '-sortdir-text'\" ui-grid-visible=\"col.sort.direction\"
		 * aria-label=\"{{getSortDirectionAriaLabel()}}\">\n" + " <i ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc,
		 * 'ui-grid-icon-blank': !col.sort.direction }\" title=\"{{isSortPriorityVisible() ? i18n.headerCell.priority + ' ' + ( col.sort.priority + 1 ) : null}}\" aria-hidden=\"true\"></i> \n" + " <sub
		 * ui-grid-visible=\"isSortPriorityVisible()\" class=\"ui-grid-sort-priority-number\">{{col.sort.priority + 1}}</sub>\n" + " </span>\n" + " </div>\n" + " <div role=\"button\" tabindex=\"0\"
		 * ui-grid-one-bind-id-grid=\"col.uid + '-menu-button'\" class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader && col.colDef.enableColumnMenu !== false\"
		 * ng-click=\"toggleMenu($event)\" ng-keydown=\"headerCellArrowKeyDown($event)\" ui-grid-one-bind-aria-label=\"i18n.headerCell.aria.columnMenuButtonLabel\" aria-haspopup=\"true\">\n" + " <i
		 * class=\"ui-grid-icon-angle-down\" aria-hidden=\"true\">&nbsp;</i>\n" + " </div>\n" + " <div ui-grid-filter></div>\n" + "</div>" );
		 * 
		 * $templateCache.put('ui-grid/ui-grid-row', "" + "<div ng-repeat=\"(colRenderIndex, col) in colContainer.renderedColumns track by col.uid\"" + " ui-grid-one-bind-id-grid=\"rowRenderIndex + '-' +
		 * col.uid + '-cell'\" class=\"ui-grid-cell\"" + " ng-class=\"{ 'ui-grid-row-header-cell': col.isRowHeader }\" " + " role=\"{{col.isRowHeader ? 'rowheader' : 'gridcell'}}\"" + " ui-grid-cell>\n" +"</div>" );
		 */
	}
})(angular);